Skip to content

Commit a1cb117

Browse files
committed
Refactor column config to support local and backend storage dynamically
1 parent bf9c97e commit a1cb117

File tree

3 files changed

+135
-40
lines changed

3 files changed

+135
-40
lines changed

keep-ui/entities/presets/model/usePresetColumnState.ts

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,33 @@ import { TimeFormatOption } from "@/widgets/alerts-table/lib/alert-table-time-fo
66
import { ListFormatOption } from "@/widgets/alerts-table/lib/alert-table-list-format";
77
import { ColumnRenameMapping } from "@/widgets/alerts-table/ui/alert-table-column-rename";
88
import { DEFAULT_COLS, DEFAULT_COLS_VISIBILITY } from "@/widgets/alerts-table/lib/alert-table-utils";
9-
import { usePresets } from "./usePresets";
109

1110
interface UsePresetColumnStateOptions {
1211
presetName: string;
1312
presetId?: string;
1413
useBackend?: boolean; // Flag to enable backend usage
1514
}
1615

16+
// Static preset IDs that should always use local storage
17+
const STATIC_PRESET_IDS = [
18+
"11111111-1111-1111-1111-111111111111", // FEED_PRESET_ID
19+
"11111111-1111-1111-1111-111111111113", // DISMISSED_PRESET_ID
20+
"11111111-1111-1111-1111-111111111114", // GROUPS_PRESET_ID
21+
"11111111-1111-1111-1111-111111111115", // WITHOUT_INCIDENT_PRESET_ID
22+
];
23+
1724
export const usePresetColumnState = ({
1825
presetName,
1926
presetId,
2027
useBackend = false,
2128
}: UsePresetColumnStateOptions) => {
29+
// Check if this is a static preset that should always use local storage
30+
const isStaticPreset = !presetId || STATIC_PRESET_IDS.includes(presetId);
31+
const shouldUseBackend = useBackend && !isStaticPreset;
32+
2233
// Backend-based state
2334
const { columnConfig, updateColumnConfig, isLoading } = usePresetColumnConfig({
24-
presetId: useBackend ? presetId : undefined
35+
presetId: shouldUseBackend ? presetId : undefined
2536
});
2637

2738
// Local storage fallbacks (existing implementation)
@@ -52,94 +63,99 @@ export const usePresetColumnState = ({
5263

5364
// Determine which state to use
5465
const columnVisibility = useMemo(() => {
55-
if (useBackend && columnConfig.column_visibility && Object.keys(columnConfig.column_visibility).length > 0) {
66+
if (shouldUseBackend && columnConfig.column_visibility && Object.keys(columnConfig.column_visibility).length > 0) {
5667
return columnConfig.column_visibility;
5768
}
5869
return localColumnVisibility;
59-
}, [useBackend, columnConfig.column_visibility, localColumnVisibility]);
70+
}, [shouldUseBackend, columnConfig.column_visibility, localColumnVisibility]);
6071

6172
const columnOrder = useMemo(() => {
62-
if (useBackend && columnConfig.column_order && columnConfig.column_order.length > 0) {
73+
if (shouldUseBackend && columnConfig.column_order && columnConfig.column_order.length > 0) {
6374
return columnConfig.column_order;
6475
}
6576
return localColumnOrder;
66-
}, [useBackend, columnConfig.column_order, localColumnOrder]);
77+
}, [shouldUseBackend, columnConfig.column_order, localColumnOrder]);
6778

6879
const columnRenameMapping = useMemo(() => {
69-
if (useBackend && columnConfig.column_rename_mapping) {
80+
if (shouldUseBackend && columnConfig.column_rename_mapping) {
7081
return columnConfig.column_rename_mapping;
7182
}
7283
return localColumnRenameMapping;
73-
}, [useBackend, columnConfig.column_rename_mapping, localColumnRenameMapping]);
84+
}, [shouldUseBackend, columnConfig.column_rename_mapping, localColumnRenameMapping]);
7485

7586
const columnTimeFormats = useMemo(() => {
76-
if (useBackend && columnConfig.column_time_formats) {
87+
if (shouldUseBackend && columnConfig.column_time_formats) {
7788
return columnConfig.column_time_formats as Record<string, TimeFormatOption>;
7889
}
7990
return localColumnTimeFormats;
80-
}, [useBackend, columnConfig.column_time_formats, localColumnTimeFormats]);
91+
}, [shouldUseBackend, columnConfig.column_time_formats, localColumnTimeFormats]);
8192

8293
const columnListFormats = useMemo(() => {
83-
if (useBackend && columnConfig.column_list_formats) {
94+
if (shouldUseBackend && columnConfig.column_list_formats) {
8495
return columnConfig.column_list_formats as Record<string, ListFormatOption>;
8596
}
8697
return localColumnListFormats;
87-
}, [useBackend, columnConfig.column_list_formats, localColumnListFormats]);
98+
}, [shouldUseBackend, columnConfig.column_list_formats, localColumnListFormats]);
8899

89-
// Update functions
100+
// Update functions - keep them synchronous for local storage, async only for backend
90101
const setColumnVisibility = useCallback(
91-
async (visibility: VisibilityState) => {
92-
if (useBackend) {
93-
await updateColumnConfig({ column_visibility: visibility });
102+
(visibility: VisibilityState) => {
103+
if (shouldUseBackend) {
104+
return updateColumnConfig({ column_visibility: visibility });
94105
} else {
95106
setLocalColumnVisibility(visibility);
107+
return Promise.resolve(); // Return resolved promise for consistency
96108
}
97109
},
98-
[useBackend, updateColumnConfig, setLocalColumnVisibility]
110+
[shouldUseBackend, updateColumnConfig, setLocalColumnVisibility]
99111
);
100112

101113
const setColumnOrder = useCallback(
102-
async (order: ColumnOrderState) => {
103-
if (useBackend) {
104-
await updateColumnConfig({ column_order: order });
114+
(order: ColumnOrderState) => {
115+
if (shouldUseBackend) {
116+
return updateColumnConfig({ column_order: order });
105117
} else {
106118
setLocalColumnOrder(order);
119+
return Promise.resolve(); // Return resolved promise for consistency
107120
}
108121
},
109-
[useBackend, updateColumnConfig, setLocalColumnOrder]
122+
[shouldUseBackend, updateColumnConfig, setLocalColumnOrder]
110123
);
111124

112125
const setColumnRenameMapping = useCallback(
113-
async (mapping: ColumnRenameMapping) => {
114-
if (useBackend) {
115-
await updateColumnConfig({ column_rename_mapping: mapping });
126+
(mapping: ColumnRenameMapping) => {
127+
if (shouldUseBackend) {
128+
return updateColumnConfig({ column_rename_mapping: mapping });
116129
} else {
117130
setLocalColumnRenameMapping(mapping);
131+
return Promise.resolve(); // Return resolved promise for consistency
118132
}
119133
},
120-
[useBackend, updateColumnConfig, setLocalColumnRenameMapping]
134+
[shouldUseBackend, updateColumnConfig, setLocalColumnRenameMapping]
121135
);
122136

123137
const setColumnTimeFormats = useCallback(
124-
async (formats: Record<string, TimeFormatOption>) => {
125-
if (useBackend) {
126-
await updateColumnConfig({ column_time_formats: formats });
138+
(formats: Record<string, TimeFormatOption>) => {
139+
if (shouldUseBackend) {
140+
return updateColumnConfig({ column_time_formats: formats });
127141
} else {
128142
setLocalColumnTimeFormats(formats);
143+
return Promise.resolve(); // Return resolved promise for consistency
129144
}
130145
},
131-
[useBackend, updateColumnConfig, setLocalColumnTimeFormats]
146+
[shouldUseBackend, updateColumnConfig, setLocalColumnTimeFormats]
132147
);
133148

134149
const setColumnListFormats = useCallback(
135-
async (formats: Record<string, ListFormatOption>) => {
136-
if (useBackend) {
137-
await updateColumnConfig({ column_list_formats: formats });
150+
(formats: Record<string, ListFormatOption>) => {
151+
if (shouldUseBackend) {
152+
return updateColumnConfig({ column_list_formats: formats });
138153
} else {
139154
setLocalColumnListFormats(formats);
155+
return Promise.resolve(); // Return resolved promise for consistency
140156
}
141157
},
142-
[useBackend, updateColumnConfig, setLocalColumnListFormats]
158+
[shouldUseBackend, updateColumnConfig, setLocalColumnListFormats]
143159
);
144160

145161
return {
@@ -154,7 +170,7 @@ export const usePresetColumnState = ({
154170
setColumnTimeFormats,
155171
setColumnListFormats,
156172
isLoading,
157-
useBackend,
173+
useBackend: shouldUseBackend,
158174
};
159175
};
160176

keep-ui/widgets/alerts-table/ui/ColumnSelection.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ export default function ColumnSelection({
2626
}: AlertColumnsSelectProps) {
2727
const tableColumns = table.getAllColumns();
2828

29-
// Use the new unified column state hook
30-
// For now, we'll use backend if presetId is provided, otherwise fall back to local storage
29+
// Use the unified column state hook - it will automatically determine
30+
// whether to use backend or local storage based on preset type
3131
const {
3232
columnVisibility,
3333
columnOrder,
@@ -38,7 +38,7 @@ export default function ColumnSelection({
3838
} = usePresetColumnState({
3939
presetName,
4040
presetId,
41-
useBackend: !!presetId, // Enable backend usage when preset ID is available
41+
useBackend: !!presetId, // Try to use backend if preset ID is available
4242
});
4343

4444
const [searchTerm, setSearchTerm] = useState("");
@@ -77,6 +77,7 @@ export default function ColumnSelection({
7777
);
7878

7979
try {
80+
// Both setters now return promises for consistency
8081
await Promise.all([
8182
setColumnVisibility(newColumnVisibility),
8283
setColumnOrder(finalOrder)
@@ -128,10 +129,10 @@ export default function ColumnSelection({
128129
className="mt-4"
129130
color="orange"
130131
type="submit"
131-
loading={isLoading}
132-
disabled={isLoading}
132+
loading={useBackend && isLoading}
133+
disabled={useBackend && isLoading}
133134
>
134-
{isLoading ? "Saving..." : "Save changes"}
135+
{useBackend && isLoading ? "Saving..." : "Save changes"}
135136
</Button>
136137
</form>
137138
);

test-column-config.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Column Configuration Test Guide
2+
3+
This guide helps verify that the new backend-based column configuration works correctly while maintaining backward compatibility.
4+
5+
## Test Cases
6+
7+
### 1. Static Preset (Feed) - Should Use Local Storage
8+
```bash
9+
# Navigate to: http://localhost:3000/alerts/feed
10+
# Expected behavior: Uses local storage, no "Synced across devices" indicator
11+
```
12+
13+
**Steps:**
14+
1. Go to `/alerts/feed`
15+
2. Click Settings (gear icon) → Columns tab
16+
3. **Verify**: No "Synced across devices" badge shown
17+
4. Enable some columns (e.g., search for "tags" and enable tag columns)
18+
5. Click "Save changes"
19+
6. Refresh page → columns should persist (from local storage)
20+
7. Open in incognito/another browser → columns should NOT be shared
21+
22+
### 2. Dynamic Preset - Should Use Backend
23+
```bash
24+
# Navigate to: http://localhost:3000/alerts/[dynamic-preset-name]
25+
# Where [dynamic-preset-name] is a user-created preset
26+
# Expected behavior: Uses backend, shows "Synced across devices" indicator
27+
```
28+
29+
**Steps:**
30+
1. Create a new preset or use existing dynamic preset
31+
2. Go to `/alerts/[preset-name]`
32+
3. Click Settings → Columns tab
33+
4. **Verify**: "Synced across devices" badge is shown
34+
5. Configure columns
35+
6. Click "Save changes"
36+
7. Open in another browser/device → columns should be shared
37+
38+
### 3. E2E Test Fix Verification
39+
```bash
40+
# Run the specific failing test
41+
cd /workspace
42+
poetry run pytest tests/e2e_tests/incidents_alerts_tests/test_filtering_sort_search_on_alerts.py::test_multi_sort_asc_dsc -v
43+
```
44+
45+
**Expected result:** Test should pass because:
46+
- Feed preset uses local storage (as before)
47+
- Column selection works synchronously
48+
- `tags.customerName` column appears in table header after enabling
49+
50+
## API Testing
51+
52+
### Test Backend Endpoints (for dynamic presets only)
53+
```bash
54+
# Get column config
55+
curl -X GET "http://localhost:8080/preset/{preset-id}/column-config" \
56+
-H "Authorization: Bearer {token}"
57+
58+
# Update column config
59+
curl -X PUT "http://localhost:8080/preset/{preset-id}/column-config" \
60+
-H "Content-Type: application/json" \
61+
-H "Authorization: Bearer {token}" \
62+
-d '{
63+
"column_visibility": {"name": true, "tags.customerName": true},
64+
"column_order": ["severity", "status", "name", "tags.customerName"]
65+
}'
66+
```
67+
68+
## Troubleshooting
69+
70+
### If E2E test still fails:
71+
1. Check that static preset IDs are correct
72+
2. Verify local storage fallback is working
73+
3. Ensure column visibility updates are synchronous for local storage
74+
75+
### If backend config doesn't work:
76+
1. Check preset has valid (non-static) ID
77+
2. Verify API endpoints are accessible
78+
3. Check network requests in browser devtools

0 commit comments

Comments
 (0)