Skip to content

Commit 73dbcdd

Browse files
plugin: Highlight Allocated state on GameServer detail view (#35)
Signed-off-by: ashwani yadav <22ashwaniyadav@gmail.com>
1 parent a703e05 commit 73dbcdd

3 files changed

Lines changed: 138 additions & 1 deletion

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright Contributors to Agones a Series of LF Projects, LLC.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
import { describe, expect, it } from 'vitest';
19+
import { GameServerStatusBanner } from './GameServerStatusBanner';
20+
21+
describe('GameServerStatusBanner', () => {
22+
describe('Allocated state', () => {
23+
it('should render a banner for Allocated state', () => {
24+
const element = React.createElement(GameServerStatusBanner, { state: 'Allocated' });
25+
expect(element).toBeDefined();
26+
expect(element.props.state).toBe('Allocated');
27+
// Component should not return null for Allocated
28+
expect(element.type).toBe(GameServerStatusBanner);
29+
});
30+
});
31+
32+
describe('Non-highlighted states', () => {
33+
it.each(['Ready', 'Creating', 'Scheduled', 'Shutdown', 'Error', 'Unhealthy', ''])(
34+
'should return null for "%s" state (no banner needed)',
35+
state => {
36+
const result = GameServerStatusBanner({ state });
37+
expect(result).toBeNull();
38+
}
39+
);
40+
});
41+
42+
describe('Edge cases', () => {
43+
it('should handle "__proto__" safely without crashing', () => {
44+
const result = GameServerStatusBanner({ state: '__proto__' });
45+
expect(result).toBeNull();
46+
});
47+
48+
it('should handle "constructor" safely without crashing', () => {
49+
const result = GameServerStatusBanner({ state: 'constructor' });
50+
expect(result).toBeNull();
51+
});
52+
53+
it('should handle "toString" safely without crashing', () => {
54+
const result = GameServerStatusBanner({ state: 'toString' });
55+
expect(result).toBeNull();
56+
});
57+
});
58+
});
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright Contributors to Agones a Series of LF Projects, LLC.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import Alert from '@mui/material/Alert';
18+
import AlertTitle from '@mui/material/AlertTitle';
19+
import React from 'react';
20+
21+
/**
22+
* Configuration for each state that should display a prominent banner
23+
* on the GameServer detail view.
24+
*
25+
* @see {@link https://agones.dev/site/docs/reference/gameserver/#gameserver-state-diagram | Agones GameServer State Diagram}
26+
*/
27+
const STATE_BANNERS: Record<
28+
string,
29+
{ severity: 'warning' | 'error' | 'info' | 'success'; title: string; message: string }
30+
> = {
31+
Allocated: {
32+
severity: 'warning',
33+
title: 'Allocated — Active Game Session',
34+
message:
35+
'This GameServer has been allocated to a game session. ' +
36+
'Players may be connected. Avoid deleting or modifying it while the session is active.',
37+
},
38+
};
39+
40+
interface GameServerStatusBannerProps {
41+
state: string;
42+
}
43+
44+
/**
45+
* Renders a prominent status banner at the top of the GameServer detail view
46+
* for states that need special attention (e.g., Allocated).
47+
*
48+
* Returns `null` for states that don't require a banner.
49+
*
50+
* @see {@link https://github.com/agones-dev/headlamp-plugin/issues/29 | Issue #29}
51+
*/
52+
export function GameServerStatusBanner({ state }: GameServerStatusBannerProps) {
53+
const config = Object.prototype.hasOwnProperty.call(STATE_BANNERS, state)
54+
? STATE_BANNERS[state]
55+
: null;
56+
57+
if (!config) {
58+
return null;
59+
}
60+
61+
return (
62+
<Alert
63+
severity={config.severity}
64+
variant="standard"
65+
sx={{
66+
mb: 2,
67+
'& .MuiAlert-icon': {
68+
fontSize: '1.5rem',
69+
},
70+
}}
71+
>
72+
<AlertTitle sx={{ fontWeight: 600 }}>{config.title}</AlertTitle>
73+
{config.message}
74+
</Alert>
75+
);
76+
}

src/views/gameservers/Detail.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import TableRow from '@mui/material/TableRow';
2525
import React from 'react';
2626
import { useParams } from 'react-router-dom';
2727
import { FleetLink } from '../../components/FleetLink';
28+
import { GameServerStatusBanner } from '../../components/GameServerStatusBanner';
29+
import { StateChip } from '../../components/StateChip';
2830
import { UtilBar } from '../../components/UtilBar';
2931
import { GameServer } from '../../resources/gameserver';
3032

@@ -202,14 +204,15 @@ export function GameServerDetail() {
202204
'—'
203205
),
204206
},
205-
{ name: 'State', value: item.state },
207+
{ name: 'State', value: <StateChip state={item.state} /> },
206208
{ name: 'Address', value: item.address || '—' },
207209
{ name: 'Ports', value: item.ports || '—' },
208210
{ name: 'Node', value: item.nodeName || '—' },
209211
]
210212
}
211213
extraSections={item =>
212214
item && [
215+
<GameServerStatusBanner state={item.state} />,
213216
<PortsSection gameServer={item} />,
214217
<CountersListsSection gameServer={item} />,
215218
<ConfigurationSection gameServer={item} />,

0 commit comments

Comments
 (0)