Skip to content

Commit c64bfff

Browse files
committed
feat: add configurable maximum windows feature with settings integration
1 parent 2a40d0f commit c64bfff

File tree

7 files changed

+217
-1
lines changed

7 files changed

+217
-1
lines changed

CONFIGURABLE_MAX_WINDOWS.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# Configurable Maximum Windows Feature
2+
3+
## Overview
4+
5+
This feature makes the maximum window limit configurable through the application's settings, addressing the limitation of hardcoded values (50 for Electron, 15 for Web) in the codebase.
6+
7+
## Changes Made
8+
9+
### 1. Core Type Definition
10+
11+
**File**: `packages/altair-core/src/types/state/settings.interfaces.ts`
12+
13+
Added a new optional property to the `SettingsState` interface:
14+
15+
```typescript
16+
/**
17+
* Maximum number of windows/tabs allowed
18+
* @default 50 (Electron), 15 (Web)
19+
*/
20+
maxWindows?: number;
21+
```
22+
23+
This property allows users to override the default maximum window limits based on their workflow needs and hardware capabilities.
24+
25+
### 2. Settings Reducer Update
26+
27+
**File**: `packages/altair-app/src/app/modules/altair/store/settings/settings.reducer.ts`
28+
29+
Updated the `getInitialState()` function to include the default `maxWindows` value from `AltairConfig`:
30+
31+
```typescript
32+
export const getInitialState = (): SettingsState => {
33+
const altairConfig = getAltairConfig();
34+
const initialSettings = altairConfig.initialData.settings ?? {};
35+
return {
36+
theme: altairConfig.defaultTheme,
37+
language: <SettingsLanguage>altairConfig.default_language,
38+
addQueryDepthLimit: altairConfig.add_query_depth_limit,
39+
tabSize: altairConfig.tab_size,
40+
maxWindows: altairConfig.max_windows, // NEW
41+
...initialSettings,
42+
};
43+
};
44+
```
45+
46+
This ensures that the default value from `AltairConfig` (50 for Electron, 15 for Web) is used unless overridden by the user.
47+
48+
### 3. Window Switcher Component
49+
50+
**File**: `packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.ts`
51+
52+
Changed `maxWindowCount` from a class property initialized with `AltairConfig` to an input signal that receives the value from settings:
53+
54+
```typescript
55+
// Before:
56+
maxWindowCount = this.altairConfig.max_windows;
57+
58+
// After:
59+
readonly maxWindowCount = input(this.altairConfig.max_windows);
60+
```
61+
62+
This allows the component to reactively update when the setting changes.
63+
64+
### 4. Header Component Template
65+
66+
**File**: `packages/altair-app/src/app/modules/altair/components/header/header.component.html`
67+
68+
Added the `maxWindowCount` binding to pass the setting value to the window switcher:
69+
70+
```html
71+
<app-window-switcher
72+
[windows]="windows()"
73+
[windowIds]="windowIds()"
74+
[activeWindowId]="activeWindowId()"
75+
[closedWindows]="closedWindows()"
76+
[isElectron]="isElectron()"
77+
[collections]="collections()"
78+
[enableScrollbar]="settings()?.enableTablistScrollbar"
79+
[maxWindowCount]="settings()?.maxWindows" <!-- NEW -->
80+
(newWindowChange)="newWindowChange.emit($event)"
81+
...
82+
/>
83+
```
84+
85+
### 5. Internationalization
86+
87+
**File**: `packages/altair-app/src/assets/i18n/en-US.json`
88+
89+
Added a translation key for the setting label:
90+
91+
```json
92+
"SETTINGS_MAX_WINDOWS_TEXT": "Maximum Windows"
93+
```
94+
95+
### 6. Tests
96+
97+
**File**: `packages/altair-app/src/app/modules/altair/store/settings/settings.spec.ts`
98+
99+
Updated all test cases to include the `maxWindows` property in the mock configuration and expected results:
100+
101+
- Added `max_windows: 15` to the mock `AltairConfig`
102+
- Updated all test expectations to include `maxWindows: 15` (or `maxWindows: 50` for Electron tests)
103+
104+
## How to Use
105+
106+
### For End Users
107+
108+
1. Open Altair GraphQL Client
109+
2. Navigate to Settings (gear icon in the header)
110+
3. In the settings JSON editor, add or modify the `maxWindows` property:
111+
112+
```json
113+
{
114+
"theme": "dark",
115+
"language": "en-US",
116+
"maxWindows": 100, // Set your desired limit
117+
...
118+
}
119+
```
120+
121+
4. Click Save
122+
123+
The new limit will take effect immediately, allowing you to open more (or fewer) windows based on your preference.
124+
125+
### For Developers/Integrators
126+
127+
When embedding Altair or initializing it programmatically, you can set the initial maximum windows:
128+
129+
```typescript
130+
new AltairConfig({
131+
initialSettings: {
132+
maxWindows: 75 // Custom limit
133+
}
134+
})
135+
```
136+
137+
Or use persisted settings:
138+
139+
```typescript
140+
new AltairConfig({
141+
persistedSettings: {
142+
maxWindows: 100 // This will override user settings
143+
}
144+
})
145+
```
146+
147+
## Default Values
148+
149+
- **Electron**: 50 windows (unchanged)
150+
- **Web**: 15 windows (unchanged)
151+
152+
These defaults remain in `packages/altair-core/src/config/index.ts` and are applied automatically if the user doesn't specify a custom value.
153+
154+
## Validation
155+
156+
The feature currently doesn't include explicit validation for the `maxWindows` value. Users should:
157+
158+
- Use reasonable positive integers (e.g., 1-200)
159+
- Consider their system's memory and performance capabilities
160+
- Avoid setting the value too low (minimum 1 is recommended)
161+
162+
Future enhancements could include:
163+
- Min/max validation in the settings UI
164+
- Performance warnings for very high values
165+
- Automatic adjustment based on system resources
166+
167+
## Benefits
168+
169+
1. **Flexibility**: Power users can increase limits for complex workflows
170+
2. **Performance**: Users with limited resources can decrease limits
171+
3. **Customization**: Different environments can have different optimal limits
172+
4. **Future-proof**: Easy to adjust as hardware capabilities improve
173+
174+
## Backward Compatibility
175+
176+
This change is fully backward compatible:
177+
178+
- Existing installations will use the default values
179+
- No breaking changes to the API
180+
- Settings files without `maxWindows` will work as before
181+
- The feature is opt-in through settings
182+
183+
## Next Steps
184+
185+
To fully enable this feature in the UI:
186+
187+
1. Run `pnpm bootstrap` to build the TypeScript packages
188+
2. Run `pnpm test` to ensure all tests pass
189+
3. Test the feature manually in both Electron and Web environments
190+
4. Consider adding a UI control in the settings dialog for easier configuration
191+
5. Add validation rules to prevent unreasonable values
192+
6. Update user documentation
193+
194+
## Related Files
195+
196+
- `packages/altair-core/src/config/index.ts` - Original hardcoded limits
197+
- `packages/altair-core/src/types/state/settings.interfaces.ts` - Settings interface
198+
- `packages/altair-app/src/app/modules/altair/store/settings/settings.reducer.ts` - Settings state management
199+
- `packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.ts` - Component that uses the limit
200+
- `packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html` - Template that checks the limit
201+
- `packages/altair-app/src/app/modules/altair/components/header/header.component.html` - Passes setting to component

packages/altair-app/src/app/modules/altair/components/header/header.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
[isElectron]="isElectron()"
1616
[collections]="collections()"
1717
[enableScrollbar]="settings()?.enableTablistScrollbar"
18+
[maxWindowCount]="settings()?.maxWindows"
1819
(newWindowChange)="newWindowChange.emit($event)"
1920
(activeWindowChange)="activeWindowChange.emit($event)"
2021
(removeWindowChange)="removeWindowChange.emit($event)"

packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export class WindowSwitcherComponent {
2828
readonly activeWindowId = input('');
2929
readonly isElectron = input(false);
3030
readonly enableScrollbar = input(false);
31+
readonly maxWindowCount = input(this.altairConfig.max_windows);
3132
readonly activeWindowChange = output<string>();
3233
readonly newWindowChange = output();
3334
readonly removeWindowChange = output<string>();
@@ -44,7 +45,6 @@ export class WindowSwitcherComponent {
4445
}
4546

4647
windowIdEditing = '';
47-
maxWindowCount = this.altairConfig.max_windows;
4848

4949
onDropEnd(event: CdkDragDrop<any, any, any>) {
5050
this.moveWindow(event.previousIndex || 0, event.currentIndex || 0);

packages/altair-app/src/app/modules/altair/store/settings/settings.reducer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const getInitialState = (): SettingsState => {
1515
language: <SettingsLanguage>altairConfig.default_language,
1616
addQueryDepthLimit: altairConfig.add_query_depth_limit,
1717
tabSize: altairConfig.tab_size,
18+
maxWindows: altairConfig.max_windows,
1819
...initialSettings,
1920
};
2021
};

packages/altair-app/src/app/modules/altair/store/settings/settings.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ let mockAltairConfig = {
88
default_language: 'en-US',
99
add_query_depth_limit: 1,
1010
tab_size: 1,
11+
max_windows: 15,
1112
};
1213
jest.mock('altair-graphql-core/build/config', () => {
1314
return {
@@ -27,6 +28,7 @@ describe('settings', () => {
2728
default_language: 'en-US',
2829
add_query_depth_limit: 1,
2930
tab_size: 1,
31+
max_windows: 15,
3032
};
3133
});
3234
it('should return previous state if action is not known', () => {
@@ -46,6 +48,7 @@ describe('settings', () => {
4648
language: 'en-US',
4749
addQueryDepthLimit: 1,
4850
tabSize: 1,
51+
maxWindows: 15,
4952
});
5053
});
5154

@@ -61,6 +64,7 @@ describe('settings', () => {
6164
default_language: 'en-US',
6265
add_query_depth_limit: 1,
6366
tab_size: 1,
67+
max_windows: 15,
6468
};
6569
const newState = settingsReducer(undefined, {
6670
type: 'UNKNOWN_ACTION',
@@ -71,6 +75,7 @@ describe('settings', () => {
7175
language: 'en-US',
7276
addQueryDepthLimit: 1,
7377
tabSize: 1,
78+
maxWindows: 15,
7479
});
7580
});
7681

@@ -97,6 +102,7 @@ describe('settings', () => {
97102
language: 'en-US',
98103
addQueryDepthLimit: 3,
99104
tabSize: 2,
105+
maxWindows: 50,
100106
});
101107
});
102108

packages/altair-app/src/assets/i18n/en-US.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"SETTINGS_LANGUAGE_TEXT": "Language",
9797
"SETTINGS_ADD_QUERY_DEPTH_LIMIT_TEXT": "Add Query Depth Limit",
9898
"SETTINGS_TAB_SIZE_TEXT": "Tab Size",
99+
"SETTINGS_MAX_WINDOWS_TEXT": "Maximum Windows",
99100
"SETTINGS_HELP_WITH_TRANSLATIONS_TEXT": "Would you like to help with translations?",
100101
"SETTINGS_SHOW_EDITOR_HINT": "Press ctrl-space to show hint",
101102
"SETTINGS_KEYBOARD_SHORTCUTS": "Keyboard shortcuts",

packages/altair-core/src/types/state/settings.interfaces.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ export interface SettingsState {
192192
* Whether target GraphQL server supports deprecation of input values
193193
*/
194194
'introspection.options.inputValueDeprecation'?: boolean;
195+
196+
/**
197+
* Maximum number of windows/tabs allowed
198+
* @default 50 (Electron), 15 (Web)
199+
*/
200+
maxWindows?: number;
195201
}
196202

197203
// Partial settings state for generating partial validator

0 commit comments

Comments
 (0)