diff --git a/packages/hoppscotch-selfhost-web/src/api/mutations/CreateUserSettings.graphql b/packages/hoppscotch-selfhost-web/src/api/mutations/CreateUserSettings.graphql new file mode 100644 index 000000000..2ada8a1fa --- /dev/null +++ b/packages/hoppscotch-selfhost-web/src/api/mutations/CreateUserSettings.graphql @@ -0,0 +1,5 @@ +mutation CreateUserSettings($properties: String!) { + createUserSettings(properties: $properties) { + id + } +} diff --git a/packages/hoppscotch-selfhost-web/src/api/mutations/UpdateUserSettings.graphql b/packages/hoppscotch-selfhost-web/src/api/mutations/UpdateUserSettings.graphql new file mode 100644 index 000000000..85bb4b0e6 --- /dev/null +++ b/packages/hoppscotch-selfhost-web/src/api/mutations/UpdateUserSettings.graphql @@ -0,0 +1,5 @@ +mutation UpdateUserSettings($properties: String!) { + updateUserSettings(properties: $properties) { + id + } +} diff --git a/packages/hoppscotch-selfhost-web/src/api/queries/GetUserSettings.graphql b/packages/hoppscotch-selfhost-web/src/api/queries/GetUserSettings.graphql new file mode 100644 index 000000000..1ac94553e --- /dev/null +++ b/packages/hoppscotch-selfhost-web/src/api/queries/GetUserSettings.graphql @@ -0,0 +1,8 @@ +query GetUserSettings { + me { + settings { + id + properties + } + } +} diff --git a/packages/hoppscotch-selfhost-web/src/api/subscriptions/UserSettingsUpdated.graphql b/packages/hoppscotch-selfhost-web/src/api/subscriptions/UserSettingsUpdated.graphql new file mode 100644 index 000000000..4b8f6a6e7 --- /dev/null +++ b/packages/hoppscotch-selfhost-web/src/api/subscriptions/UserSettingsUpdated.graphql @@ -0,0 +1,6 @@ +subscription UserSettingsUpdated { + userSettingsUpdated { + id + properties + } +} diff --git a/packages/hoppscotch-selfhost-web/src/lib/sync/index.ts b/packages/hoppscotch-selfhost-web/src/lib/sync/index.ts index aa5e9d294..1427e600d 100644 --- a/packages/hoppscotch-selfhost-web/src/lib/sync/index.ts +++ b/packages/hoppscotch-selfhost-web/src/lib/sync/index.ts @@ -30,7 +30,7 @@ export const getSyncInitFunction = >( store: T, storeSyncDefinition: StoreSyncDefinitionOf, shouldSyncValue: () => boolean, - shouldSyncObservable: Observable + shouldSyncObservable?: Observable ) => { let startSubscriptions: () => () => void | undefined let stopSubscriptions: () => void | undefined @@ -38,15 +38,16 @@ export const getSyncInitFunction = >( 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) => { diff --git a/packages/hoppscotch-selfhost-web/src/main.ts b/packages/hoppscotch-selfhost-web/src/main.ts index 93a663532..b4788d171 100644 --- a/packages/hoppscotch-selfhost-web/src/main.ts +++ b/packages/hoppscotch-selfhost-web/src/main.ts @@ -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, }, }) diff --git a/packages/hoppscotch-selfhost-web/src/platform/settings/settings.api.ts b/packages/hoppscotch-selfhost-web/src/platform/settings/settings.api.ts new file mode 100644 index 000000000..07872cd44 --- /dev/null +++ b/packages/hoppscotch-selfhost-web/src/platform/settings/settings.api.ts @@ -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, + }) diff --git a/packages/hoppscotch-selfhost-web/src/platform/settings/settings.platform.ts b/packages/hoppscotch-selfhost-web/src/platform/settings/settings.platform.ts new file mode 100644 index 000000000..b30252391 --- /dev/null +++ b/packages/hoppscotch-selfhost-web/src/platform/settings/settings.platform.ts @@ -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[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, +} diff --git a/packages/hoppscotch-selfhost-web/src/platform/settings/settings.sync.ts b/packages/hoppscotch-selfhost-web/src/platform/settings/settings.sync.ts new file mode 100644 index 000000000..19df5001a --- /dev/null +++ b/packages/hoppscotch-selfhost-web/src/platform/settings/settings.sync.ts @@ -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 +)