mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 12:43:09 -05:00
202 lines
5.7 KiB
TypeScript
202 lines
5.7 KiB
TypeScript
import { type ReactNode, useState } from 'react';
|
|
import { Trans } from 'react-i18next';
|
|
|
|
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 { Setting } from './UI';
|
|
|
|
import { Link } from '@desktop-client/components/common/Link';
|
|
import { Checkbox } from '@desktop-client/components/forms';
|
|
import { useFeatureFlag } from '@desktop-client/hooks/useFeatureFlag';
|
|
import { useSyncedPref } from '@desktop-client/hooks/useSyncedPref';
|
|
|
|
type FeatureToggleProps = {
|
|
flag: FeatureFlag;
|
|
disableToggle?: boolean;
|
|
error?: ReactNode;
|
|
children: ReactNode;
|
|
feedbackLink?: string;
|
|
};
|
|
|
|
function FeatureToggle({
|
|
flag: flagName,
|
|
disableToggle = false,
|
|
feedbackLink,
|
|
error,
|
|
children,
|
|
}: FeatureToggleProps) {
|
|
const enabled = useFeatureFlag(flagName);
|
|
const [_, setFlagPref] = useSyncedPref(`flags.${flagName}`);
|
|
|
|
return (
|
|
<label style={{ display: 'flex' }}>
|
|
<Checkbox
|
|
checked={enabled}
|
|
onChange={() => {
|
|
setFlagPref(String(!enabled));
|
|
}}
|
|
disabled={disableToggle}
|
|
/>
|
|
<View
|
|
style={{ color: disableToggle ? theme.pageTextSubdued : 'inherit' }}
|
|
>
|
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
|
|
{children}
|
|
{feedbackLink && (
|
|
<Link variant="external" to={feedbackLink}>
|
|
<Trans>(give feedback)</Trans>
|
|
</Link>
|
|
)}
|
|
</View>
|
|
|
|
{disableToggle && (
|
|
<Text
|
|
style={{
|
|
color: theme.errorText,
|
|
fontWeight: 500,
|
|
}}
|
|
>
|
|
{error}
|
|
</Text>
|
|
)}
|
|
</View>
|
|
</label>
|
|
);
|
|
}
|
|
|
|
type GlobalFeatureToggleProps = {
|
|
prefName: keyof SyncedPrefs;
|
|
disableToggle?: boolean;
|
|
error?: ReactNode;
|
|
children: ReactNode;
|
|
feedbackLink?: string;
|
|
};
|
|
|
|
function GlobalFeatureToggle({
|
|
prefName,
|
|
disableToggle = false,
|
|
feedbackLink,
|
|
error,
|
|
children,
|
|
}: GlobalFeatureToggleProps) {
|
|
const [enabled, setEnabled] = useSyncedPref(prefName);
|
|
|
|
return (
|
|
<label style={{ display: 'flex' }}>
|
|
<Checkbox
|
|
checked={enabled === 'true'}
|
|
onChange={() => {
|
|
setEnabled(enabled === 'true' ? 'false' : 'true');
|
|
}}
|
|
disabled={disableToggle}
|
|
/>
|
|
<View
|
|
style={{ color: disableToggle ? theme.pageTextSubdued : 'inherit' }}
|
|
>
|
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 5 }}>
|
|
{children}
|
|
{feedbackLink && (
|
|
<Link variant="external" to={feedbackLink}>
|
|
<Trans>(give feedback)</Trans>
|
|
</Link>
|
|
)}
|
|
</View>
|
|
|
|
{disableToggle && (
|
|
<Text
|
|
style={{
|
|
color: theme.errorText,
|
|
fontWeight: 500,
|
|
}}
|
|
>
|
|
{error}
|
|
</Text>
|
|
)}
|
|
</View>
|
|
</label>
|
|
);
|
|
}
|
|
|
|
export function ExperimentalFeatures() {
|
|
const [expanded, setExpanded] = useState(false);
|
|
|
|
const goalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
|
|
const goalTemplatesUIEnabled = useFeatureFlag('goalTemplatesUIEnabled');
|
|
const showGoalTemplatesUI =
|
|
goalTemplatesUIEnabled ||
|
|
(goalTemplatesEnabled &&
|
|
localStorage.getItem('devEnableGoalTemplatesUI') === 'true');
|
|
|
|
return (
|
|
<Setting
|
|
primaryAction={
|
|
expanded ? (
|
|
<View style={{ gap: '1em' }}>
|
|
<FeatureToggle flag="goalTemplatesEnabled">
|
|
<Trans>Goal templates</Trans>
|
|
</FeatureToggle>
|
|
{showGoalTemplatesUI && (
|
|
<View style={{ paddingLeft: 22 }}>
|
|
<FeatureToggle flag="goalTemplatesUIEnabled">
|
|
<Trans>Subfeature: Budget automations UI</Trans>
|
|
</FeatureToggle>
|
|
</View>
|
|
)}
|
|
<FeatureToggle
|
|
flag="actionTemplating"
|
|
feedbackLink="https://github.com/actualbudget/actual/issues/3606"
|
|
>
|
|
<Trans>Rule action templating</Trans>
|
|
</FeatureToggle>
|
|
<FeatureToggle
|
|
flag="formulaMode"
|
|
feedbackLink="https://github.com/actualbudget/actual/issues/5949"
|
|
>
|
|
<Trans>Excel formula mode (Formula cards & Rule formulas)</Trans>
|
|
</FeatureToggle>
|
|
<FeatureToggle
|
|
flag="currency"
|
|
feedbackLink="https://github.com/actualbudget/actual/issues/5191"
|
|
>
|
|
<Trans>Currency support</Trans>
|
|
</FeatureToggle>
|
|
<GlobalFeatureToggle
|
|
prefName="plugins"
|
|
disableToggle={true}
|
|
feedbackLink="https://github.com/actualbudget/actual/issues/5950"
|
|
>
|
|
<Trans>Client-Side plugins (soon)</Trans>
|
|
</GlobalFeatureToggle>
|
|
</View>
|
|
) : (
|
|
<Link
|
|
variant="text"
|
|
onClick={() => setExpanded(true)}
|
|
data-testid="experimental-settings"
|
|
style={{
|
|
flexShrink: 0,
|
|
alignSelf: 'flex-start',
|
|
color: theme.pageTextPositive,
|
|
}}
|
|
>
|
|
<Trans>I understand the risks, show experimental features</Trans>
|
|
</Link>
|
|
)
|
|
}
|
|
>
|
|
<Text>
|
|
<Trans>
|
|
<strong>Experimental features.</strong> These features are not fully
|
|
tested and may not work as expected. THEY MAY CAUSE IRRECOVERABLE DATA
|
|
LOSS. They may do nothing at all. Only enable them if you know what
|
|
you are doing.
|
|
</Trans>
|
|
</Text>
|
|
</Setting>
|
|
);
|
|
}
|