feat: implement user settings syncing for selfhost (#59)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
mutation CreateUserSettings($properties: String!) {
|
||||
createUserSettings(properties: $properties) {
|
||||
id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation UpdateUserSettings($properties: String!) {
|
||||
updateUserSettings(properties: $properties) {
|
||||
id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
query GetUserSettings {
|
||||
me {
|
||||
settings {
|
||||
id
|
||||
properties
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
subscription UserSettingsUpdated {
|
||||
userSettingsUpdated {
|
||||
id
|
||||
properties
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export const getSyncInitFunction = <T extends DispatchingStore<any, any>>(
|
||||
store: T,
|
||||
storeSyncDefinition: StoreSyncDefinitionOf<T>,
|
||||
shouldSyncValue: () => boolean,
|
||||
shouldSyncObservable: Observable<boolean>
|
||||
shouldSyncObservable?: Observable<boolean>
|
||||
) => {
|
||||
let startSubscriptions: () => () => void | undefined
|
||||
let stopSubscriptions: () => void | undefined
|
||||
@@ -38,15 +38,16 @@ export const getSyncInitFunction = <T extends DispatchingStore<any, any>>(
|
||||
let oldSyncStatus = shouldSyncValue()
|
||||
|
||||
// Start and stop the subscriptions according to the sync settings from profile
|
||||
shouldSyncObservable.subscribe((newSyncStatus) => {
|
||||
if (oldSyncStatus === true && newSyncStatus === false) {
|
||||
stopListeningToSubscriptions()
|
||||
} else if (oldSyncStatus === false && newSyncStatus === true) {
|
||||
startListeningToSubscriptions()
|
||||
}
|
||||
shouldSyncObservable &&
|
||||
shouldSyncObservable.subscribe((newSyncStatus) => {
|
||||
if (oldSyncStatus === true && newSyncStatus === false) {
|
||||
stopListeningToSubscriptions()
|
||||
} else if (oldSyncStatus === false && newSyncStatus === true) {
|
||||
startListeningToSubscriptions()
|
||||
}
|
||||
|
||||
oldSyncStatus = newSyncStatus
|
||||
})
|
||||
oldSyncStatus = newSyncStatus
|
||||
})
|
||||
|
||||
function startStoreSync() {
|
||||
store.dispatches$.subscribe((actionParams) => {
|
||||
|
||||
@@ -2,11 +2,13 @@ import { createHoppApp } from "@hoppscotch/common"
|
||||
import { def as authDef } from "./platform/auth"
|
||||
import { def as environmentsDef } from "./platform/environments/environments.platform"
|
||||
import { def as collectionsDef } from "./platform/collections/collections.platform"
|
||||
import { def as settingsDef } from "./platform/settings/settings.platform"
|
||||
|
||||
createHoppApp("#app", {
|
||||
auth: authDef,
|
||||
sync: {
|
||||
environments: environmentsDef,
|
||||
collections: collectionsDef,
|
||||
settings: settingsDef,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
runGQLQuery,
|
||||
runGQLSubscription,
|
||||
runMutation,
|
||||
} from "@hoppscotch/common/helpers/backend/GQLClient"
|
||||
import {
|
||||
CreateUserSettingsDocument,
|
||||
CreateUserSettingsMutation,
|
||||
CreateUserSettingsMutationVariables,
|
||||
GetUserSettingsDocument,
|
||||
GetUserSettingsQuery,
|
||||
GetUserSettingsQueryVariables,
|
||||
UpdateUserSettingsDocument,
|
||||
UpdateUserSettingsMutation,
|
||||
UpdateUserSettingsMutationVariables,
|
||||
UserSettingsUpdatedDocument,
|
||||
} from "../../api/generated/graphql"
|
||||
|
||||
export const getUserSettings = () =>
|
||||
runGQLQuery<
|
||||
GetUserSettingsQuery,
|
||||
GetUserSettingsQueryVariables,
|
||||
"user_settings/not_found"
|
||||
>({
|
||||
query: GetUserSettingsDocument,
|
||||
})
|
||||
|
||||
export const createUserSettings = (properties: string) =>
|
||||
runMutation<
|
||||
CreateUserSettingsMutation,
|
||||
CreateUserSettingsMutationVariables,
|
||||
""
|
||||
>(CreateUserSettingsDocument, {
|
||||
properties,
|
||||
})()
|
||||
|
||||
export const updateUserSettings = (properties: string) =>
|
||||
runMutation<
|
||||
UpdateUserSettingsMutation,
|
||||
UpdateUserSettingsMutationVariables,
|
||||
""
|
||||
>(UpdateUserSettingsDocument, {
|
||||
properties,
|
||||
})()
|
||||
|
||||
export const runUserSettingsUpdatedSubscription = () =>
|
||||
runGQLSubscription({
|
||||
query: UserSettingsUpdatedDocument,
|
||||
})
|
||||
@@ -0,0 +1,88 @@
|
||||
import { SettingsPlatformDef } from "@hoppscotch/common/platform/settings"
|
||||
import { settingsSyncer } from "./settings.sync"
|
||||
import { authEvents$, def as platformAuth } from "@platform/auth"
|
||||
import {
|
||||
createUserSettings,
|
||||
getUserSettings,
|
||||
runUserSettingsUpdatedSubscription,
|
||||
} from "./settings.api"
|
||||
import * as E from "fp-ts/Either"
|
||||
import { runGQLSubscription } from "@hoppscotch/common/helpers/backend/GQLClient"
|
||||
import {
|
||||
bulkApplySettings,
|
||||
defaultSettings,
|
||||
} from "@hoppscotch/common/newstore/settings"
|
||||
import { runDispatchWithOutSyncing } from "@lib/sync"
|
||||
|
||||
function initSettingsSync() {
|
||||
const currentUser$ = platformAuth.getCurrentUserStream()
|
||||
settingsSyncer.startStoreSync()
|
||||
settingsSyncer.setupSubscriptions(setupSubscriptions)
|
||||
|
||||
// load the settings
|
||||
|
||||
loadUserSettings()
|
||||
|
||||
currentUser$.subscribe(async (user) => {
|
||||
if (user) {
|
||||
// load the settings
|
||||
loadUserSettings()
|
||||
}
|
||||
})
|
||||
|
||||
authEvents$.subscribe((event) => {
|
||||
if (event.event == "login" || event.event == "token_refresh") {
|
||||
settingsSyncer.startListeningToSubscriptions()
|
||||
}
|
||||
|
||||
if (event.event == "logout") {
|
||||
settingsSyncer.stopListeningToSubscriptions()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function loadUserSettings() {
|
||||
const res = await getUserSettings()
|
||||
|
||||
// create user settings if it doesn't exist
|
||||
E.isLeft(res) &&
|
||||
res.left.error == "user_settings/not_found" &&
|
||||
(await createUserSettings(JSON.stringify(defaultSettings)))
|
||||
|
||||
if (E.isRight(res)) {
|
||||
runDispatchWithOutSyncing(() => {
|
||||
bulkApplySettings(JSON.parse(res.right.me.settings.properties))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function setupSubscriptions() {
|
||||
let subs: ReturnType<typeof runGQLSubscription>[1][] = []
|
||||
|
||||
const userSettingsUpdatedSub = setupUserSettingsUpdatedSubscription()
|
||||
|
||||
subs = [userSettingsUpdatedSub]
|
||||
|
||||
return () => {
|
||||
subs.forEach((sub) => sub.unsubscribe())
|
||||
}
|
||||
}
|
||||
|
||||
function setupUserSettingsUpdatedSubscription() {
|
||||
const [userSettingsUpdated$, userSettingsUpdatedSub] =
|
||||
runUserSettingsUpdatedSubscription()
|
||||
|
||||
userSettingsUpdated$.subscribe((res) => {
|
||||
if (E.isRight(res)) {
|
||||
runDispatchWithOutSyncing(() => {
|
||||
bulkApplySettings(JSON.parse(res.right.userSettingsUpdated.properties))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return userSettingsUpdatedSub
|
||||
}
|
||||
|
||||
export const def: SettingsPlatformDef = {
|
||||
initSettingsSync,
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { settingsStore } from "@hoppscotch/common/newstore/settings"
|
||||
|
||||
import { getSyncInitFunction } from "../../lib/sync"
|
||||
|
||||
import { StoreSyncDefinitionOf } from "../../lib/sync"
|
||||
|
||||
import { updateUserSettings } from "./settings.api"
|
||||
|
||||
export const settingsSyncDefinition: StoreSyncDefinitionOf<
|
||||
typeof settingsStore
|
||||
> = {
|
||||
applySetting() {
|
||||
updateUserSettings(JSON.stringify(settingsStore.value))
|
||||
},
|
||||
}
|
||||
|
||||
export const settingsSyncer = getSyncInitFunction(
|
||||
settingsStore,
|
||||
settingsSyncDefinition,
|
||||
() => true
|
||||
)
|
||||
Reference in New Issue
Block a user