diff --git a/packages/desktop-client/src/components/Modals.tsx b/packages/desktop-client/src/components/Modals.tsx
index e5e995e706..db6716d910 100644
--- a/packages/desktop-client/src/components/Modals.tsx
+++ b/packages/desktop-client/src/components/Modals.tsx
@@ -102,7 +102,9 @@ export function Modals() {
return budgetId ? : null;
case 'category-automations-edit':
- return budgetId ? : null;
+ return budgetId ? (
+
+ ) : null;
case 'keyboard-shortcuts':
// don't show the hotkey help modal when a budget is not open
diff --git a/packages/desktop-client/src/components/NotesButton.tsx b/packages/desktop-client/src/components/NotesButton.tsx
index d42753d839..3aaf11b26e 100644
--- a/packages/desktop-client/src/components/NotesButton.tsx
+++ b/packages/desktop-client/src/components/NotesButton.tsx
@@ -14,6 +14,7 @@ import { Popover } from '@actual-app/components/popover';
import { theme } from '@actual-app/components/theme';
import { Tooltip } from '@actual-app/components/tooltip';
import { View } from '@actual-app/components/view';
+import { css, cx } from '@emotion/css';
import { send } from 'loot-core/platform/client/fetch';
@@ -27,6 +28,7 @@ type NotesButtonProps = {
height?: number;
defaultColor?: string;
tooltipPosition?: ComponentProps['placement'];
+ showPlaceholder?: boolean;
style?: CSSProperties;
};
export function NotesButton({
@@ -35,6 +37,7 @@ export function NotesButton({
height = 12,
defaultColor = theme.buttonNormalText,
tooltipPosition = 'bottom start',
+ showPlaceholder = false,
style,
}: NotesButtonProps) {
const { t } = useTranslation();
@@ -73,13 +76,19 @@ export function NotesButton({
ref={triggerRef}
variant="bare"
aria-label={t('View notes')}
- className={!hasNotes && !isOpen ? 'hover-visible' : ''}
- style={{
- color: defaultColor,
- ...style,
- ...(hasNotes && { display: 'flex !important' }),
- ...(isOpen && { color: theme.buttonNormalText }),
- }}
+ className={cx(
+ css({
+ color: defaultColor,
+ ...style,
+ ...(showPlaceholder && {
+ opacity: hasNotes || isOpen ? 1 : 0.3,
+ }),
+ ...(isOpen && { color: theme.buttonNormalText }),
+ '&:hover': { opacity: 1 },
+ }),
+ !hasNotes && !isOpen && !showPlaceholder ? 'hover-visible' : '',
+ )}
+ data-placeholder={showPlaceholder}
onPress={() => {
setIsOpen(true);
}}
diff --git a/packages/desktop-client/src/components/budget/SidebarCategory.tsx b/packages/desktop-client/src/components/budget/SidebarCategory.tsx
index c9c08ec8bb..0998a01734 100644
--- a/packages/desktop-client/src/components/budget/SidebarCategory.tsx
+++ b/packages/desktop-client/src/components/budget/SidebarCategory.tsx
@@ -15,12 +15,10 @@ import {
type CategoryEntity,
} from 'loot-core/types/models';
-import { CategoryAutomationButton } from './goals/CategoryAutomationButton';
+import { SidebarCategoryButtons } from './SidebarCategoryButtons';
-import { NotesButton } from '@desktop-client/components/NotesButton';
import { InputCell } from '@desktop-client/components/table';
import { useContextMenu } from '@desktop-client/hooks/useContextMenu';
-import { useFeatureFlag } from '@desktop-client/hooks/useFeatureFlag';
import { useGlobalPref } from '@desktop-client/hooks/useGlobalPref';
type SidebarCategoryProps = {
@@ -56,7 +54,6 @@ export function SidebarCategory({
onHideNewCategory,
}: SidebarCategoryProps) {
const { t } = useTranslation();
- const isGoalTemplatesUIEnabled = useFeatureFlag('goalTemplatesUIEnabled');
const [categoryExpandedStatePref] = useGlobalPref('categoryExpandedState');
const categoryExpandedState = categoryExpandedStatePref ?? 0;
@@ -128,22 +125,11 @@ export function SidebarCategory({
/>
-
- {!goalsShown && isGoalTemplatesUIEnabled && (
-
-
-
- )}
-
-
-
+
);
diff --git a/packages/desktop-client/src/components/budget/SidebarCategoryButtons.tsx b/packages/desktop-client/src/components/budget/SidebarCategoryButtons.tsx
new file mode 100644
index 0000000000..8b549c09f1
--- /dev/null
+++ b/packages/desktop-client/src/components/budget/SidebarCategoryButtons.tsx
@@ -0,0 +1,53 @@
+import { theme } from '@actual-app/components/theme';
+import { View } from '@actual-app/components/view';
+
+import { type CategoryEntity } from 'loot-core/types/models/category';
+
+import { CategoryAutomationButton } from './goals/CategoryAutomationButton';
+
+import { NotesButton } from '@desktop-client/components/NotesButton';
+import { useFeatureFlag } from '@desktop-client/hooks/useFeatureFlag';
+import { useNotes } from '@desktop-client/hooks/useNotes';
+
+type SidebarCategoryButtonsProps = {
+ category: CategoryEntity;
+ dragging: boolean;
+ goalsShown: boolean;
+};
+
+export const SidebarCategoryButtons = ({
+ category,
+ dragging,
+ goalsShown,
+}: SidebarCategoryButtonsProps) => {
+ const isGoalTemplatesUIEnabled = useFeatureFlag('goalTemplatesUIEnabled');
+ const notes = useNotes(category.id) || '';
+
+ return (
+ <>
+
+ {!goalsShown && isGoalTemplatesUIEnabled && (
+
+
+
+ )}
+
+
+
+ >
+ );
+};
diff --git a/packages/desktop-client/src/components/budget/goals/BudgetAutomationEditor.tsx b/packages/desktop-client/src/components/budget/goals/BudgetAutomationEditor.tsx
index 67d4860ddf..1d744ddb6c 100644
--- a/packages/desktop-client/src/components/budget/goals/BudgetAutomationEditor.tsx
+++ b/packages/desktop-client/src/components/budget/goals/BudgetAutomationEditor.tsx
@@ -1,3 +1,4 @@
+import { type ReactNode } from 'react';
import { useTranslation, Trans } from 'react-i18next';
import { InitialFocus } from '@actual-app/components/initial-focus';
@@ -20,7 +21,11 @@ import { ScheduleAutomation } from './editor/ScheduleAutomation';
import { SimpleAutomation } from './editor/SimpleAutomation';
import { WeekAutomation } from './editor/WeekAutomation';
-import { FormField, FormLabel } from '@desktop-client/components/forms';
+import {
+ FormField,
+ FormLabel,
+ FormTextLabel,
+} from '@desktop-client/components/forms';
type BudgetAutomationEditorProps = {
inline: boolean;
@@ -73,7 +78,7 @@ export function BudgetAutomationEditor({
}: BudgetAutomationEditorProps) {
const { t } = useTranslation();
- let automationEditor;
+ let automationEditor: ReactNode;
switch (state.displayType) {
case 'simple':
automationEditor = (
@@ -144,7 +149,7 @@ export function BudgetAutomationEditor({
-
+
{displayTypeToDescription[state.displayType] ?? (
No description available
diff --git a/packages/desktop-client/src/components/budget/goals/CategoryAutomationButton.tsx b/packages/desktop-client/src/components/budget/goals/CategoryAutomationButton.tsx
index 078fefb23d..8a3c9e290a 100644
--- a/packages/desktop-client/src/components/budget/goals/CategoryAutomationButton.tsx
+++ b/packages/desktop-client/src/components/budget/goals/CategoryAutomationButton.tsx
@@ -4,34 +4,36 @@ import { useTranslation } from 'react-i18next';
import { Button } from '@actual-app/components/button';
import { SvgChartPie } from '@actual-app/components/icons/v1';
import { theme } from '@actual-app/components/theme';
+import { cx, css } from '@emotion/css';
-import { type Template } from 'loot-core/types/models/templates';
+import { type CategoryEntity } from 'loot-core/types/models';
import { useFeatureFlag } from '@desktop-client/hooks/useFeatureFlag';
import { pushModal } from '@desktop-client/modals/modalsSlice';
import { useDispatch } from '@desktop-client/redux';
type CategoryAutomationButtonProps = {
+ category: CategoryEntity;
width?: number;
height?: number;
defaultColor?: string;
style?: CSSProperties;
+ showPlaceholder?: boolean;
};
export function CategoryAutomationButton({
+ category,
width = 12,
height = 12,
defaultColor = theme.buttonNormalText,
style,
+ showPlaceholder = false,
}: CategoryAutomationButtonProps) {
const { t } = useTranslation();
-
- const automations: Template[] = [];
- const hasAutomations = !!automations.length;
-
const dispatch = useDispatch();
const goalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
const goalTemplatesUIEnabled = useFeatureFlag('goalTemplatesUIEnabled');
+ const hasAutomations = !!category.goal_def?.length;
if (!goalTemplatesEnabled || !goalTemplatesUIEnabled) {
return null;
@@ -41,14 +43,26 @@ export function CategoryAutomationButton({