Skip to content

Commit 3d7cc73

Browse files
authored
Merge pull request #123 from AnthonyGress/dev
fix group bugs
2 parents b89f14e + 7ee2e61 commit 3d7cc73

File tree

7 files changed

+94
-57
lines changed

7 files changed

+94
-57
lines changed

backend/src/routes/jellyseerr.route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import axios from 'axios';
2-
import { Request, response, Response, Router } from 'express';
2+
import { Request, Response, Router } from 'express';
33
import https from 'https';
44

55
import { getItemConnectionInfo } from '../utils/config-lookup';

frontend/src/components/dashboard/base-items/apps/AppShortcut.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ type Props = {
1515
editMode?: boolean;
1616
config?: any;
1717
isPreview?: boolean;
18+
size?: 'small' | 'medium' | 'large';
1819
}
1920

20-
export const AppShortcut = ({ url, name, iconName, showLabel, editMode, config, isPreview }: Props) => {
21+
export const AppShortcut = ({ url, name, iconName, showLabel, editMode, config, isPreview, size = 'medium' }: Props) => {
2122
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
2223
const isWolShortcut = config?.isWol === true;
2324

@@ -33,6 +34,14 @@ export const AppShortcut = ({ url, name, iconName, showLabel, editMode, config,
3334
return isMobile ? '.9rem' : '1rem';
3435
}, [name, isMobile]);
3536

37+
// Calculate text width based on size prop to prevent overlap with status icons
38+
const textWidth = useMemo(() => {
39+
if (size === 'small') {
40+
return '70%'; // Narrower for 4x2 layout to prevent overlap
41+
}
42+
return '80%'; // Default width for other layouts
43+
}, [size]);
44+
3645
const handleWakeOnLan = useCallback(async (e: React.MouseEvent) => {
3746
e.preventDefault();
3847

@@ -125,7 +134,7 @@ export const AppShortcut = ({ url, name, iconName, showLabel, editMode, config,
125134
WebkitLineClamp: 1,
126135
WebkitBoxOrient: 'vertical',
127136
wordBreak: 'break-word',
128-
width: '80%',
137+
width: textWidth,
129138
lineHeight: 1.2,
130139
mt: 1
131140
}}

frontend/src/components/dashboard/base-items/widgets/GroupWidget.tsx

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ const SortableGroupItem: React.FC<SortableGroupItemProps> = ({
122122
opacity: isDragging ? 0.5 : 1,
123123
position: 'relative',
124124
touchAction: 'none', // Ensure touch events are captured properly on mobile
125+
display: 'flex',
126+
justifyContent: 'center',
127+
alignItems: 'center'
125128
}}
126129
data-item-id={item.id}
127130
data-group-id={groupId}
@@ -145,6 +148,7 @@ const SortableGroupItem: React.FC<SortableGroupItemProps> = ({
145148
iconName={item.icon || ''}
146149
showLabel={true}
147150
editMode={isEditing}
151+
size={itemSize}
148152
config={{
149153
isWol: item.isWol,
150154
macAddress: item.macAddress,
@@ -259,7 +263,7 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
259263
// 4x2 grid layout (8 items in 2 rows of 4 items each)
260264
return {
261265
width: '22%', // Even narrower items, 4 per row
262-
maxWidth: '120px', // Max width for larger screens
266+
maxWidth: '180px', // Max width for larger screens
263267
rows: 2,
264268
cols: 4,
265269
height: DUAL_WIDGET_CONTAINER_HEIGHT,
@@ -470,14 +474,6 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
470474
}
471475
}, [items, onItemsChange, onItemDelete]);
472476

473-
// Handle click on add button - opens the group edit modal
474-
const handleAddClick = useCallback(() => {
475-
if (isEditing && items.length < MAX_ITEMS) {
476-
// Open the group edit modal
477-
onEdit?.();
478-
}
479-
}, [isEditing, items.length, onEdit, MAX_ITEMS]);
480-
481477
// Cleanup effects for mobile
482478
useEffect(() => {
483479
// Cleanup function to ensure we don't leave lingering event listeners
@@ -647,13 +643,22 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
647643
sx={{
648644
flex: 1,
649645
display: 'grid',
650-
gridTemplateColumns: layout === '2x3' ? 'repeat(2, 1fr)' : layout === '4x2' ? 'repeat(4, 1fr)' : 'repeat(3, 1fr)', // Explicit grid columns
651-
gap: 1, // 8px gap between items
652-
justifyItems: 'center',
653-
alignItems: 'center',
646+
gridTemplateColumns: layout === '2x3'
647+
? { xs: 'repeat(2, minmax(110px, 180px))', sm: 'repeat(2, minmax(90px, 160px))' }
648+
: layout === '4x2'
649+
? { xs: 'repeat(4, minmax(70px, 110px))', sm: 'repeat(4, minmax(75px, 140px))', md: 'repeat(4, minmax(85px, 160px))', lg: 'repeat(4, minmax(95px, 180px))' }
650+
: { xs: 'repeat(3, minmax(95px, 160px))', sm: 'repeat(3, minmax(85px, 150px))' },
651+
gridTemplateRows: layout === '2x3' ? 'repeat(3, auto)' : layout === '4x2' ? 'repeat(2, auto)' : 'repeat(1, auto)',
652+
rowGap: layout === '4x2' ? { xs: 3, sm: 4 } : { xs: 4, sm: 4 },
653+
columnGap: layout === '4x2' ? { xs: 1, sm: 2 } : { xs: 2, sm: 4 },
654+
gridAutoFlow: 'row', // Fill row by row (left to right, top to bottom)
655+
justifyItems: layout === '4x2' ? 'stretch' : 'center', // Stretch 4x2 items to fill grid cells, center others
656+
alignItems: 'center', // Center items vertically within their grid cells
657+
justifyContent: 'center', // Center the grid content horizontally
658+
alignContent: 'center', // Center the entire grid vertically
654659
overflowY: 'hidden',
655660
overflowX: 'hidden',
656-
p: { lg: 2 },
661+
p: 1,
657662
m: 0
658663
}}
659664
>
@@ -664,8 +669,10 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
664669
sx={{
665670
display: 'flex',
666671
justifyContent: 'center',
667-
maxWidth: gridSettings.maxWidth,
668-
width: '100%'
672+
alignItems: 'center',
673+
maxWidth: layout === '4x2' ? 'none' : gridSettings.maxWidth,
674+
width: '100%',
675+
height: '100%'
669676
}}
670677
>
671678
<SortableGroupItem
@@ -727,8 +734,10 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
727734
sx={{
728735
display: 'flex',
729736
justifyContent: 'center',
730-
maxWidth: gridSettings.maxWidth,
731-
width: '100%'
737+
alignItems: 'center',
738+
maxWidth: layout === '4x2' ? 'none' : gridSettings.maxWidth,
739+
width: '100%',
740+
height: '100%'
732741
}}
733742
>
734743
<Box
@@ -746,7 +755,6 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
746755
backgroundColor: 'rgba(255, 255, 255, 0.05)'
747756
}
748757
}}
749-
onClick={handleAddClick}
750758
title='Edit group to add items'
751759
>
752760
<AddIcon fontSize='medium' />

frontend/src/components/dashboard/sortable-items/widgets/SortableGroupWidget.tsx

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ export const SortableGroupWidget: React.FC<Props> = ({
7575

7676
// Handle item changes (reordering within the group)
7777
const handleItemsChange = useCallback(async (newItems: GroupItem[]) => {
78-
if (!config) return;
78+
// Ensure config exists with defaults for new groups
79+
const safeConfig = config || { maxItems: '3', showLabel: true, items: [] };
7980

8081
// Update the group widget config directly using saveLayout instead of updateItem
8182
// to avoid triggering any unexpected state changes
@@ -84,7 +85,8 @@ export const SortableGroupWidget: React.FC<Props> = ({
8485
return {
8586
...layoutItem,
8687
config: {
87-
...layoutItem.config,
88+
...safeConfig, // Use safeConfig which includes defaults
89+
...layoutItem.config, // Preserve any existing config
8890
items: newItems
8991
}
9092
};
@@ -97,7 +99,7 @@ export const SortableGroupWidget: React.FC<Props> = ({
9799

98100
// Update local state to reflect the change
99101
setDashboardLayout(updatedLayout);
100-
}, [id, config, dashboardLayout, saveLayout, setDashboardLayout]);
102+
}, [id, dashboardLayout, saveLayout, setDashboardLayout, config]);
101103

102104
// Get a group item as a dashboard item for editing
103105
const getItemAsDashboardItem = useCallback((itemId: string): DashboardItem | null => {
@@ -150,7 +152,9 @@ export const SortableGroupWidget: React.FC<Props> = ({
150152

151153
// Function to update a group item after it has been edited
152154
const updateGroupItem = useCallback(async (itemId: string, updatedItem: DashboardItem) => {
153-
if (!config?.items) return;
155+
// Ensure config exists with defaults for new groups
156+
const safeConfig = config || { maxItems: '3', showLabel: true, items: [] };
157+
const currentItems = safeConfig.items || [];
154158

155159
// Create an updated GroupItem from the updated DashboardItem
156160
const updatedGroupItem: GroupItem = {
@@ -176,7 +180,7 @@ export const SortableGroupWidget: React.FC<Props> = ({
176180
}
177181

178182
// Replace the item in the group's items array
179-
const updatedItems = config.items.map(item =>
183+
const updatedItems = currentItems.map(item =>
180184
item.id === itemId ? updatedGroupItem : item
181185
);
182186

@@ -187,7 +191,8 @@ export const SortableGroupWidget: React.FC<Props> = ({
187191
return {
188192
...layoutItem,
189193
config: {
190-
...layoutItem.config,
194+
...safeConfig, // Use safeConfig which includes defaults
195+
...layoutItem.config, // Preserve any existing config
191196
items: updatedItems
192197
}
193198
};
@@ -200,7 +205,7 @@ export const SortableGroupWidget: React.FC<Props> = ({
200205

201206
// Update local state to reflect the change
202207
setDashboardLayout(updatedLayout);
203-
}, [config, id, dashboardLayout, saveLayout, setDashboardLayout]);
208+
}, [id, dashboardLayout, saveLayout, setDashboardLayout, config]);
204209

205210
// Function to notify about dragging a group item
206211
const notifyGroupItemDrag = useCallback((isDragging: boolean, itemId?: string) => {
@@ -320,17 +325,22 @@ export const SortableGroupWidget: React.FC<Props> = ({
320325

321326
// Add an app shortcut to the group
322327
const addAppShortcutToGroup = useCallback((shortcutItem: DashboardItem) => {
323-
if (!config || !dashboardLayout) {
324-
console.error('Missing config or dashboardLayout');
328+
if (!dashboardLayout) {
329+
console.error('Missing dashboardLayout');
325330
return;
326331
}
327332

333+
// Ensure config exists with defaults for new groups
334+
const safeConfig = config || { maxItems: '3', showLabel: true, items: [] };
335+
328336
// Use the configured maxItems or parse from the special format strings
329-
const maxItemsStr = String(config.maxItems || 3);
337+
const maxItemsStr = String(safeConfig.maxItems || 3);
330338
let MAX_ITEMS = 3;
331339

332340
if (maxItemsStr === '6_2x3' || maxItemsStr === '6_3x2') {
333341
MAX_ITEMS = 6;
342+
} else if (maxItemsStr === '8_4x2') {
343+
MAX_ITEMS = 8;
334344
} else {
335345
MAX_ITEMS = parseInt(maxItemsStr, 10) || 3;
336346
}
@@ -400,7 +410,8 @@ export const SortableGroupWidget: React.FC<Props> = ({
400410
}
401411

402412
updatedGroupWidget.config = {
403-
...updatedGroupWidget.config,
413+
...safeConfig, // Use safeConfig which includes defaults
414+
...updatedGroupWidget.config, // Preserve any existing config
404415
items: updatedItems
405416
};
406417

@@ -411,7 +422,7 @@ export const SortableGroupWidget: React.FC<Props> = ({
411422

412423
// Save to server
413424
saveLayout(updatedLayout);
414-
}, [dashboardLayout, config, id, ensureItems, setDashboardLayout, saveLayout]);
425+
}, [dashboardLayout, id, ensureItems, setDashboardLayout, saveLayout, config]);
415426

416427
// Get maximum items allowed in the group
417428
const getMaxItems = useCallback(() => {

frontend/src/components/forms/AddEditForm.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,9 @@ export const AddEditForm = ({ handleClose, existingItem, onSubmit }: Props) => {
975975
} else if (data.widgetType === ITEM_TYPE.RADARR_WIDGET) {
976976
// Radarr widget configuration
977977
config = await createWidgetConfig(ITEM_TYPE.RADARR_WIDGET, data);
978+
} else if (data.widgetType === ITEM_TYPE.GROUP_WIDGET) {
979+
// Group widget configuration
980+
config = await createWidgetConfig(ITEM_TYPE.GROUP_WIDGET, data);
978981
} else if (data.widgetType === ITEM_TYPE.DUAL_WIDGET) {
979982
// Check if DualWidgetConfig component has already built the config
980983
const existingConfig = (formContext as any).getValues('config');
@@ -1656,6 +1659,12 @@ export const AddEditForm = ({ handleClose, existingItem, onSubmit }: Props) => {
16561659
}
16571660
};
16581661
}
1662+
} else if (widgetType === ITEM_TYPE.GROUP_WIDGET) {
1663+
return {
1664+
maxItems: data.maxItems || '3', // Default to 3 items layout
1665+
showLabel: data.showLabel !== undefined ? data.showLabel : true, // Default to showing label
1666+
items: existingItem?.config?.items || [] // Preserve existing items or start with empty array
1667+
};
16591668
}
16601669

16611670
return {};

0 commit comments

Comments
 (0)