Centralize default user and team preferences. (#5172

Passing the fallback at each callpoint was dumb
This commit is contained in:
Tom Moor
2023-04-09 17:23:58 -04:00
committed by GitHub
parent 8324b03938
commit 2f9a56aa6f
11 changed files with 67 additions and 39 deletions

View File

@@ -1,4 +1,5 @@
import { computed, observable } from "mobx";
import { TeamPreferenceDefaults } from "@shared/constants";
import { TeamPreference, TeamPreferences } from "@shared/types";
import { stringToColor } from "@shared/utils/color";
import BaseModel from "./BaseModel";
@@ -88,22 +89,19 @@ class Team extends BaseModel {
*/
@computed
get seamlessEditing(): boolean {
return !!this.getPreference(TeamPreference.SeamlessEdit, true);
return !!this.getPreference(TeamPreference.SeamlessEdit);
}
/**
* Get the value for a specific preference key, or return the fallback if
* none is set.
* Returns the value of the provided preference.
*
* @param key The TeamPreference key to retrieve
* @param fallback An optional fallback value, defaults to false.
* @returns The value
* @param preference The team preference to retrieve
* @returns The preference value if set, else the default value
*/
getPreference<T extends keyof TeamPreferences>(
key: T,
fallback = false
key: T
): TeamPreferences[T] | false {
return this.preferences?.[key] ?? fallback;
return this.preferences?.[key] ?? TeamPreferenceDefaults[key] ?? false;
}
/**

View File

@@ -7,6 +7,7 @@ import { useLocation, Link, Redirect } from "react-router-dom";
import styled from "styled-components";
import { getCookie, setCookie } from "tiny-cookie";
import { s } from "@shared/styles";
import { UserPreference } from "@shared/types";
import { parseDomain } from "@shared/utils/domains";
import { Config } from "~/stores/AuthStore";
import ButtonLarge from "~/components/ButtonLarge";
@@ -61,7 +62,9 @@ function Login({ children }: Props) {
const [error, setError] = React.useState(null);
const [emailLinkSentTo, setEmailLinkSentTo] = React.useState("");
const isCreate = location.pathname === "/create";
const rememberLastPath = !!auth.user?.preferences?.rememberLastPath;
const rememberLastPath = !!auth.user?.getPreference(
UserPreference.RememberLastPath
);
const [lastVisitedPath] = useLastVisitedPath();
const handleReset = React.useCallback(() => {

View File

@@ -53,7 +53,7 @@ function Features() {
<Switch
id={TeamPreference.SeamlessEdit}
name={TeamPreference.SeamlessEdit}
checked={team.getPreference(TeamPreference.SeamlessEdit, true)}
checked={team.getPreference(TeamPreference.SeamlessEdit)}
onChange={handlePreferenceChange}
/>
</SettingRow>
@@ -71,7 +71,7 @@ function Features() {
<Switch
id={TeamPreference.Commenting}
name={TeamPreference.Commenting}
checked={team.getPreference(TeamPreference.Commenting, false)}
checked={team.getPreference(TeamPreference.Commenting)}
onChange={handlePreferenceChange}
/>
</SettingRow>
@@ -86,7 +86,7 @@ function Features() {
<Switch
id={TeamPreference.PublicBranding}
name={TeamPreference.PublicBranding}
checked={team.getPreference(TeamPreference.PublicBranding, false)}
checked={team.getPreference(TeamPreference.PublicBranding)}
onChange={handlePreferenceChange}
/>
</SettingRow>

View File

@@ -87,29 +87,29 @@ function Preferences() {
/>
</SettingRow>
<SettingRow
name="useCursorPointer"
name={UserPreference.UseCursorPointer}
label={t("Use pointer cursor")}
description={t(
"Show a hand cursor when hovering over interactive elements."
)}
>
<Switch
id="useCursorPointer"
name="useCursorPointer"
checked={user.getPreference(UserPreference.UseCursorPointer, true)}
id={UserPreference.UseCursorPointer}
name={UserPreference.UseCursorPointer}
checked={user.getPreference(UserPreference.UseCursorPointer)}
onChange={handlePreferenceChange}
/>
</SettingRow>
<SettingRow
name="codeBlockLineNumbers"
name={UserPreference.CodeBlockLineNumers}
label={t("Show line numbers")}
description={t("Show line numbers on code blocks in documents.")}
border={false}
>
<Switch
id="codeBlockLineNumbers"
name="codeBlockLineNumbers"
checked={user.getPreference(UserPreference.CodeBlockLineNumers, true)}
id={UserPreference.CodeBlockLineNumers}
name={UserPreference.CodeBlockLineNumers}
checked={user.getPreference(UserPreference.CodeBlockLineNumers)}
onChange={handlePreferenceChange}
/>
</SettingRow>
@@ -117,16 +117,16 @@ function Preferences() {
<Heading as="h2">{t("Behavior")}</Heading>
<SettingRow
border={false}
name="rememberLastPath"
name={UserPreference.RememberLastPath}
label={t("Remember previous location")}
description={t(
"Automatically return to the document you were last viewing when the app is re-opened."
)}
>
<Switch
id="rememberLastPath"
name="rememberLastPath"
checked={!!user.preferences?.rememberLastPath}
id={UserPreference.RememberLastPath}
name={UserPreference.RememberLastPath}
checked={!!user.getPreference(UserPreference.RememberLastPath)}
onChange={handlePreferenceChange}
/>
</SettingRow>

View File

@@ -264,7 +264,7 @@ function Security() {
>
<Switch
id={TeamPreference.ViewersCanExport}
checked={team.getPreference(TeamPreference.ViewersCanExport, true)}
checked={team.getPreference(TeamPreference.ViewersCanExport)}
onChange={handlePreferenceChange}
/>
</SettingRow>

View File

@@ -20,6 +20,7 @@ import {
AllowNull,
AfterUpdate,
} from "sequelize-typescript";
import { TeamPreferenceDefaults } from "@shared/constants";
import {
CollectionPermission,
TeamPreference,
@@ -196,14 +197,15 @@ class Team extends ParanoidModel {
};
/**
* Returns the passed preference value
* Returns the value of the given preference.
*
* @param preference The user preference to retrieve
* @param fallback An optional fallback value, defaults to false.
* @returns The preference value if set, else undefined
* @param preference The team preference to retrieve
* @returns The preference value if set, else the default value
*/
public getPreference = (preference: TeamPreference, fallback = false) =>
this.preferences?.[preference] ?? fallback;
public getPreference = (preference: TeamPreference) =>
this.preferences?.[preference] ??
TeamPreferenceDefaults[preference] ??
false;
provisionFirstCollection = async (userId: string) => {
await this.sequelize!.transaction(async (transaction) => {

View File

@@ -22,6 +22,7 @@ import {
AllowNull,
AfterUpdate,
} from "sequelize-typescript";
import { UserPreferenceDefaults } from "@shared/constants";
import { languages } from "@shared/i18n";
import type { NotificationSettings } from "@shared/types";
import {
@@ -354,14 +355,15 @@ class User extends ParanoidModel {
};
/**
* Returns the passed preference value
* Returns the value of the givem preference
*
* @param preference The user preference to retrieve
* @param fallback An optional fallback value, defaults to false.
* @returns The preference value if set, else undefined
* @returns The preference value if set, else the default value.
*/
public getPreference = (preference: UserPreference, fallback = false) =>
this.preferences?.[preference] ?? fallback;
public getPreference = (preference: UserPreference) =>
this.preferences?.[preference] ??
UserPreferenceDefaults[preference] ??
false;
collectionIds = async (options = {}) => {
const collectionStubs = await Collection.scope({

View File

@@ -35,7 +35,7 @@ allow(User, "download", Document, (user, document) => {
if (
user.isViewer &&
!user.team.getPreference(TeamPreference.ViewersCanExport, true)
!user.team.getPreference(TeamPreference.ViewersCanExport)
) {
return false;
}

View File

@@ -1,9 +1,10 @@
import { TeamPreference } from "@shared/types";
import { Team } from "@server/models";
export default function presentPublicTeam(team: Team) {
return {
name: team.name,
avatarUrl: team.avatarUrl,
customTheme: team.preferences?.customTheme,
customTheme: team.getPreference(TeamPreference.CustomTheme),
};
}

View File

@@ -1,3 +1,24 @@
import {
TeamPreference,
TeamPreferences,
UserPreference,
UserPreferences,
} from "./types";
export const USER_PRESENCE_INTERVAL = 5000;
export const MAX_AVATAR_DISPLAY = 6;
export const TeamPreferenceDefaults: TeamPreferences = {
[TeamPreference.SeamlessEdit]: true,
[TeamPreference.ViewersCanExport]: true,
[TeamPreference.PublicBranding]: false,
[TeamPreference.Commenting]: false,
[TeamPreference.CustomTheme]: undefined,
};
export const UserPreferenceDefaults: UserPreferences = {
[UserPreference.RememberLastPath]: true,
[UserPreference.UseCursorPointer]: true,
[UserPreference.CodeBlockLineNumers]: true,
};

View File

@@ -107,6 +107,7 @@ export enum UserPreference {
RememberLastPath = "rememberLastPath",
/** If web-style hand pointer should be used on interactive elements. */
UseCursorPointer = "useCursorPointer",
/** Whether code blocks should show line numbers. */
CodeBlockLineNumers = "codeBlockLineNumbers",
}