Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Foundations for the budget automations UI #4308

Merged
merged 2 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/component-library/src/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,10 @@ export const styles: Record<string, any> = {
lightScrollbar: null as CSSProperties | null,
darkScrollbar: null as CSSProperties | null,
scrollbarWidth: null as number | null,
editorPill: {
color: theme.pillText,
backgroundColor: theme.pillBackground,
borderRadius: 4,
padding: '3px 5px',
},
Comment on lines +151 to +156
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unused in the current PR, but the next PR will use the same styles in a different component so I extracted it here

};
14 changes: 14 additions & 0 deletions packages/desktop-client/src/components/budget/SidebarCategory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from 'loot-core/types/models';

import { useContextMenu } from '../../hooks/useContextMenu';
import { useFeatureFlag } from '../../hooks/useFeatureFlag';
import { SvgCheveronDown } from '../../icons/v1';
import { theme } from '../../style';
import { Button } from '../common/Button2';
Expand All @@ -17,13 +18,16 @@ import { View } from '../common/View';
import { NotesButton } from '../NotesButton';
import { InputCell } from '../table';

import { CategoryAutomationButton } from './goals/CategoryAutomationButton';

type SidebarCategoryProps = {
innerRef: Ref<HTMLDivElement>;
category: CategoryEntity;
categoryGroup?: CategoryGroupEntity;
dragPreview?: boolean;
dragging?: boolean;
editing: boolean;
goalsShown?: boolean;
style?: CSSProperties;
borderColor?: string;
isLast?: boolean;
Expand All @@ -40,6 +44,7 @@ export function SidebarCategory({
dragPreview,
dragging,
editing,
goalsShown = false,
style,
isLast,
onEditName,
Expand All @@ -48,6 +53,7 @@ export function SidebarCategory({
onHideNewCategory,
}: SidebarCategoryProps) {
const { t } = useTranslation();
const goalTemplatesUIEnabled = useFeatureFlag('goalTemplatesUIEnabled');

const temporary = category.id === 'new';
const { setMenuOpen, menuOpen, handleContextMenu, resetPosition, position } =
Expand Down Expand Up @@ -128,6 +134,14 @@ export function SidebarCategory({
</Popover>
</View>
<View style={{ flex: 1 }} />
{!goalsShown && goalTemplatesUIEnabled && (
<View style={{ flexShrink: 0 }}>
<CategoryAutomationButton
style={dragging && { color: 'currentColor' }}
defaultColor={theme.pageTextLight}
/>
</View>
)}
<View style={{ flexShrink: 0 }}>
<NotesButton
id={category.id}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { type CSSProperties } from 'react';

import { Button } from '@actual-app/components/button';
import { theme } from '@actual-app/components/theme';

import { pushModal } from 'loot-core/client/actions';
import { type Template } from 'loot-core/server/budget/types/templates';

import { useFeatureFlag } from '../../../hooks/useFeatureFlag';
import { SvgChartPie } from '../../../icons/v1';
import { useDispatch } from '../../../redux';

type CategoryAutomationButtonProps = {
width?: number;
height?: number;
defaultColor?: string;
style?: CSSProperties;
};
export function CategoryAutomationButton({
width = 12,
height = 12,
defaultColor = theme.buttonNormalText,
style,
}: CategoryAutomationButtonProps) {
const automations: Template[] = [];
const hasAutomations = !!automations.length;

const dispatch = useDispatch();

const goalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
const goalTemplatesUIEnabled = useFeatureFlag('goalTemplatesUIEnabled');

if (!goalTemplatesEnabled || !goalTemplatesUIEnabled) {
return null;
}

return (
<Button
variant="bare"
aria-label="Change category automations"
className={!hasAutomations ? 'hover-visible' : ''}
style={{
color: defaultColor,
...style,
...(hasAutomations && { display: 'flex !important' }),
}}
onPress={() => {
dispatch(pushModal('category-automations-edit'));
}}
>
<SvgChartPie style={{ width, height, flexShrink: 0 }} />
</Button>
);
}
19 changes: 3 additions & 16 deletions packages/desktop-client/src/components/modals/EditRuleModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,7 @@ function FieldError({ type }) {
function Editor({ error, style, children }) {
return (
<View style={style} data-testid="editor-row">
<Stack
direction="row"
align="center"
spacing={1}
style={{
padding: '3px 5px',
}}
>
<Stack direction="row" align="center" spacing={1}>
{children}
</Stack>
{error && <FieldError type={error} />}
Expand Down Expand Up @@ -1008,12 +1001,6 @@ export function EditRuleModal({ defaultRule, onSave: originalOnSave }) {
}
}

const editorStyle = {
color: theme.pillText,
backgroundColor: theme.pillBackground,
borderRadius: 4,
};

// Enable editing existing split rules even if the feature has since been disabled.
const showSplitButton = actionSplits.length > 0;

Expand Down Expand Up @@ -1104,7 +1091,7 @@ export function EditRuleModal({ defaultRule, onSave: originalOnSave }) {
<ConditionsList
conditionsOp={conditionsOp}
conditions={conditions}
editorStyle={editorStyle}
editorStyle={styles.editorPill}
isSchedule={isSchedule}
onChangeConditions={conds => setConditions(conds)}
/>
Expand Down Expand Up @@ -1185,7 +1172,7 @@ export function EditRuleModal({ defaultRule, onSave: originalOnSave }) {
'append-notes',
]}
action={action}
editorStyle={editorStyle}
editorStyle={styles.editorPill}
onChange={(name, value) => {
onChangeAction(action, name, value);
}}
Expand Down
14 changes: 14 additions & 0 deletions packages/desktop-client/src/components/settings/Experimental.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ function FeatureToggle({
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={
Expand All @@ -78,6 +85,13 @@ export function ExperimentalFeatures() {
<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"
Expand Down
1 change: 1 addition & 0 deletions packages/desktop-client/src/hooks/useFeatureFlag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useSyncedPref } from './useSyncedPref';

const DEFAULT_FEATURE_FLAG_STATE: Record<FeatureFlag, boolean> = {
goalTemplatesEnabled: false,
goalTemplatesUIEnabled: false,
actionTemplating: false,
contextMenus: false,
openidAuth: false,
Expand Down
1 change: 1 addition & 0 deletions packages/loot-core/src/client/data-hooks/schedules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export function useSchedules({
setError(undefined);

if (!query) {
console.error('No query provided to useSchedules');
return;
}

Expand Down
1 change: 1 addition & 0 deletions packages/loot-core/src/client/state-types/modals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ type FinanceModals = {
};
'keyboard-shortcuts': EmptyObject;
'goal-templates': EmptyObject;
'category-automations-edit': EmptyObject;
};

export type PushModalAction = {
Expand Down
2 changes: 1 addition & 1 deletion packages/loot-core/src/server/budget/types/templates.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ interface AverageTemplate extends BaseTemplate {
}

interface GoalTemplate extends BaseTemplate {
type: 'simple';
type: 'goal';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed since I'm pretty sure it's a typo, will matter later once we implement goal-type templates

amount: number;
}

Expand Down
1 change: 1 addition & 0 deletions packages/loot-core/src/types/prefs.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export type FeatureFlag =
| 'goalTemplatesEnabled'
| 'goalTemplatesUIEnabled'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling this goalTemplatesUIEnabled rather than budgetAutomationsUIEnabled so the flags are consistent (and a search in the codebase for goalTemplates in the future will find all usages)

| 'actionTemplating'
| 'contextMenus'
| 'openidAuth';
Expand Down
6 changes: 6 additions & 0 deletions upcoming-release-notes/4308.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Features
authors: [jfdoming]
---

Foundations for the budget automations UI