From fed1cd7d308e7d3cfa7c1f0d54317db43a0521a7 Mon Sep 17 00:00:00 2001 From: lelemm Date: Fri, 9 Jan 2026 05:17:36 -0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Added=20Global=20Synced=20Prefs=20(?= =?UTF-8?q?#6234)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Global Synced Prefs * [autofix.ci] apply automated fixes * Add release notes for PR #6234 * typecheck * lint fix * Refactor global synced preferences to server preferences - Removed global synced preferences implementation and related files. - Introduced server preferences with a new slice and hooks for managing user settings. - Updated components and hooks to utilize server preferences instead of global synced preferences. - Adjusted Redux store and mock configurations to reflect the changes. - Enhanced user settings consistency across devices with the new server preferences structure. * Implement server preferences for feature flags and enhance admin permissions - Updated the Experimental component to conditionally display based on user permissions and login method. - Refactored feature flag handling to use 'flags.plugins' instead of 'plugins'. - Introduced server-side checks to restrict access to server preferences for admin users only. - Added comprehensive tests for server preferences management, ensuring proper handling of user roles and preferences. * Enhance error handling in saveServerPrefs thunk - Updated the saveServerPrefs async thunk to handle potential errors from the server response. - Added a check for the presence of an error in the result and return it accordingly. - Ensured that preferences are still dispatched to the store upon successful save. * Feedback: strict "flags.plugins" typing * Feedback: move state slice * Feedback: localstorage pref * Feedback: move serverPrefsSlide into prefsSlice * Refactor: Remove duplicate import of PostError in app.ts * Rename serverPrefs state slice property to server (#6596) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] Co-authored-by: Matiss Janis Aboltins Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> --- .../src/components/settings/Experimental.tsx | 59 ++++-- .../src/hooks/useFeatureFlag.ts | 1 - .../desktop-client/src/hooks/useServerPref.ts | 31 +++ .../desktop-client/src/prefs/prefsSlice.ts | 54 ++++- packages/loot-core/src/server/auth/app.ts | 2 + .../loot-core/src/server/preferences/app.ts | 31 +++ packages/loot-core/src/types/prefs.ts | 6 +- .../1763873568237-server-global-prefs.js | 19 ++ packages/sync-server/src/account-db.js | 27 +++ packages/sync-server/src/app-account.js | 29 +++ packages/sync-server/src/app-account.test.js | 195 ++++++++++++++++++ upcoming-release-notes/6234.md | 6 + 12 files changed, 442 insertions(+), 18 deletions(-) create mode 100644 packages/desktop-client/src/hooks/useServerPref.ts create mode 100644 packages/sync-server/migrations/1763873568237-server-global-prefs.js create mode 100644 packages/sync-server/src/app-account.test.js create mode 100644 upcoming-release-notes/6234.md diff --git a/packages/desktop-client/src/components/settings/Experimental.tsx b/packages/desktop-client/src/components/settings/Experimental.tsx index 341ec1014a..34b8955499 100644 --- a/packages/desktop-client/src/components/settings/Experimental.tsx +++ b/packages/desktop-client/src/components/settings/Experimental.tsx @@ -5,14 +5,22 @@ import { Text } from '@actual-app/components/text'; import { theme } from '@actual-app/components/theme'; import { View } from '@actual-app/components/view'; -import type { FeatureFlag, SyncedPrefs } from 'loot-core/types/prefs'; +import type { FeatureFlag, ServerPrefs } from 'loot-core/types/prefs'; import { Setting } from './UI'; +import { useAuth } from '@desktop-client/auth/AuthProvider'; +import { Permissions } from '@desktop-client/auth/types'; import { Link } from '@desktop-client/components/common/Link'; import { Checkbox } from '@desktop-client/components/forms'; +import { + useLoginMethod, + useMultiuserEnabled, +} from '@desktop-client/components/ServerContext'; import { useFeatureFlag } from '@desktop-client/hooks/useFeatureFlag'; +import { useServerPref } from '@desktop-client/hooks/useServerPref'; import { useSyncedPref } from '@desktop-client/hooks/useSyncedPref'; +import { useSyncServerStatus } from '@desktop-client/hooks/useSyncServerStatus'; type FeatureToggleProps = { flag: FeatureFlag; @@ -68,22 +76,42 @@ function FeatureToggle({ ); } -type GlobalFeatureToggleProps = { - prefName: keyof SyncedPrefs; +type ServerFeatureToggleProps = { + prefName: keyof ServerPrefs; disableToggle?: boolean; error?: ReactNode; children: ReactNode; feedbackLink?: string; }; -function GlobalFeatureToggle({ +function ServerFeatureToggle({ prefName, disableToggle = false, feedbackLink, error, children, -}: GlobalFeatureToggleProps) { - const [enabled, setEnabled] = useSyncedPref(prefName); +}: ServerFeatureToggleProps) { + const [enabled, setEnabled] = useServerPref(prefName); + + const syncServerStatus = useSyncServerStatus(); + const isUsingServer = syncServerStatus !== 'no-server'; + const isServerOffline = syncServerStatus === 'offline'; + const { hasPermission } = useAuth(); + const loginMethod = useLoginMethod(); + const multiuserEnabled = useMultiuserEnabled(); + + if (!isUsingServer || isServerOffline) { + return null; + } + + // Show to admins if OIDC is enabled, or to everyone if multi-user is not enabled + const isAdmin = hasPermission(Permissions.ADMINISTRATOR); + const oidcEnabled = loginMethod === 'openid'; + const shouldShow = (oidcEnabled && isAdmin) || !multiuserEnabled; + + if (!shouldShow) { + return null; + } return (