Skip to content

Commit b3799a0

Browse files
committed
update environments listing page
1 parent 9a8329e commit b3799a0

File tree

2 files changed

+333
-126
lines changed

2 files changed

+333
-126
lines changed

client/packages/lowcoder/src/pages/setting/environments/EnvironmentsList.tsx

Lines changed: 198 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import React, { useState } from "react";
2-
import { Typography, Alert, Input, Button, Space, Empty } from "antd";
3-
import { SearchOutlined, ReloadOutlined } from "@ant-design/icons";
2+
import { Typography, Alert, Input, Button, Space, Empty, Card, Spin, Row, Col, Tooltip, Badge } from "antd";
3+
import { SearchOutlined, ReloadOutlined, PlusOutlined, EnvironmentOutlined } from "@ant-design/icons";
44
import { useHistory } from "react-router-dom";
55
import { useEnvironmentContext } from "./context/EnvironmentContext";
66
import { Environment } from "./types/environment.types";
77
import EnvironmentsTable from "./components/EnvironmentsTable";
88
import { buildEnvironmentId } from "@lowcoder-ee/constants/routesURL";
9-
import EditEnvironmentModal from "./components/EditEnvironmentModal";
9+
import { getEnvironmentTagColor } from "./utils/environmentUtils";
1010

11-
const { Title } = Typography;
11+
const { Title, Text } = Typography;
1212

1313
/**
1414
* Environment Listing Page Component
@@ -19,13 +19,13 @@ const EnvironmentsList: React.FC = () => {
1919
const {
2020
environments,
2121
isLoading,
22-
error,
22+
error,
23+
refreshEnvironments
2324
} = useEnvironmentContext();
2425

25-
console.log("Environments:", environments);
26-
2726
// State for search input
2827
const [searchText, setSearchText] = useState("");
28+
const [isRefreshing, setIsRefreshing] = useState(false);
2929

3030
// Hook for navigation
3131
const history = useHistory();
@@ -46,20 +46,160 @@ const EnvironmentsList: React.FC = () => {
4646
history.push(buildEnvironmentId(record.environmentId));
4747
};
4848

49+
// Handle refresh
50+
const handleRefresh = async () => {
51+
setIsRefreshing(true);
52+
await refreshEnvironments();
53+
setIsRefreshing(false);
54+
};
55+
56+
// Count environment types
57+
const environmentCounts = environments.reduce((counts, env) => {
58+
const type = env.environmentType.toUpperCase();
59+
counts[type] = (counts[type] || 0) + 1;
60+
return counts;
61+
}, {} as Record<string, number>);
62+
4963
return (
50-
<div className="environments-container" style={{ padding: "24px", flex:1 }}>
51-
{/* Header section with title and controls */}
64+
<div
65+
className="environments-container"
66+
style={{
67+
padding: "24px",
68+
flex: 1,
69+
minWidth: "1000px",
70+
// Ensure minimum width to prevent excessive shrinking
71+
}}
72+
>
73+
{/* Modern gradient header */}
5274
<div
5375
className="environments-header"
5476
style={{
5577
marginBottom: "24px",
56-
display: "flex",
57-
justifyContent: "space-between",
58-
alignItems: "center",
78+
background: 'linear-gradient(135deg, #0050b3 0%, #1890ff 100%)',
79+
padding: '24px 32px',
80+
borderRadius: '12px',
81+
color: 'white',
82+
boxShadow: '0 4px 12px rgba(0,0,0,0.1)'
5983
}}
6084
>
61-
<Title level={3}>Environments</Title>
62-
<Space>
85+
<Row justify="space-between" align="middle" gutter={[16, 16]}>
86+
<Col xs={24} sm={16}>
87+
<div style={{ display: 'flex', alignItems: 'center', gap: '20px' }}>
88+
<div style={{
89+
fontSize: '36px',
90+
backgroundColor: 'rgba(255,255,255,0.2)',
91+
width: '72px',
92+
height: '72px',
93+
borderRadius: '50%',
94+
display: 'flex',
95+
alignItems: 'center',
96+
justifyContent: 'center',
97+
boxShadow: '0 4px 8px rgba(0,0,0,0.1)'
98+
}}>
99+
<EnvironmentOutlined />
100+
</div>
101+
<div>
102+
<Title level={2} style={{ margin: '0 0 4px 0', color: 'white' }}>
103+
Environments
104+
</Title>
105+
<Text style={{ color: 'rgba(255,255,255,0.85)', fontSize: '16px' }}>
106+
Manage your deployment environments across dev, test, preprod, and production
107+
</Text>
108+
</div>
109+
</div>
110+
</Col>
111+
<Col xs={24} sm={8} style={{ textAlign: 'right' }}>
112+
<Space size="middle">
113+
<Button
114+
icon={<ReloadOutlined spin={isRefreshing} />}
115+
onClick={handleRefresh}
116+
type="primary"
117+
ghost
118+
loading={isLoading && !isRefreshing}
119+
size="large"
120+
>
121+
Refresh
122+
</Button>
123+
<Button
124+
icon={<PlusOutlined />}
125+
type="primary"
126+
size="large"
127+
>
128+
New Environment
129+
</Button>
130+
</Space>
131+
</Col>
132+
</Row>
133+
</div>
134+
135+
{/* Environment type stats */}
136+
{environments.length > 0 && (
137+
<Row gutter={[16, 16]} style={{ marginBottom: '24px' }}>
138+
<Col span={24}>
139+
<Card
140+
title="Environment Overview"
141+
style={{
142+
borderRadius: '12px',
143+
boxShadow: '0 2px 8px rgba(0,0,0,0.05)'
144+
}}
145+
headStyle={{
146+
borderBottom: '1px solid #f0f0f0',
147+
padding: '16px 24px'
148+
}}
149+
bodyStyle={{ padding: '24px' }}
150+
>
151+
<Row gutter={[32, 16]} justify="space-around">
152+
<Col>
153+
<Tooltip title="Total number of environments">
154+
<div style={{ textAlign: 'center' }}>
155+
<div style={{ fontSize: '38px', fontWeight: 600, color: '#1890ff' }}>
156+
{environments.length}
157+
</div>
158+
<div style={{ fontSize: '14px', color: '#8c8c8c', marginTop: '4px' }}>
159+
Total Environments
160+
</div>
161+
</div>
162+
</Tooltip>
163+
</Col>
164+
165+
{['PROD', 'PREPROD', 'TEST', 'DEV'].map(type => (
166+
<Col key={type}>
167+
<Tooltip title={`Number of ${type} environments`}>
168+
<div style={{ textAlign: 'center' }}>
169+
<div style={{
170+
fontSize: '38px',
171+
fontWeight: 600,
172+
color: getEnvironmentTagColor(type) === 'default' ? '#8c8c8c' : getEnvironmentTagColor(type)
173+
}}>
174+
{environmentCounts[type] || 0}
175+
</div>
176+
<div style={{ fontSize: '14px', color: '#8c8c8c', marginTop: '4px', display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '6px' }}>
177+
<Badge color={getEnvironmentTagColor(type)} />
178+
{type} Environments
179+
</div>
180+
</div>
181+
</Tooltip>
182+
</Col>
183+
))}
184+
</Row>
185+
</Card>
186+
</Col>
187+
</Row>
188+
)}
189+
190+
{/* Main content card */}
191+
<Card
192+
title="Environment List"
193+
style={{
194+
borderRadius: '12px',
195+
boxShadow: '0 2px 8px rgba(0,0,0,0.05)',
196+
}}
197+
headStyle={{
198+
borderBottom: '1px solid #f0f0f0',
199+
padding: '16px 24px'
200+
}}
201+
bodyStyle={{ padding: '24px' }}
202+
extra={
63203
<Input
64204
placeholder="Search environments"
65205
value={searchText}
@@ -68,34 +208,52 @@ const EnvironmentsList: React.FC = () => {
68208
prefix={<SearchOutlined />}
69209
allowClear
70210
/>
71-
</Space>
72-
</div>
211+
}
212+
>
213+
{/* Error handling */}
214+
{error && (
215+
<Alert
216+
message="Error loading environments"
217+
description={error}
218+
type="error"
219+
showIcon
220+
style={{ marginBottom: "24px" }}
221+
/>
222+
)}
73223

74-
{/* Error handling */}
75-
{error && (
76-
<Alert
77-
message="Error loading environments"
78-
description={error}
79-
type="error"
80-
showIcon
81-
style={{ marginBottom: "24px" }}
82-
/>
83-
)}
224+
{/* Loading, empty state or table */}
225+
{isLoading ? (
226+
<div style={{ display: 'flex', justifyContent: 'center', padding: '60px 0' }}>
227+
<Spin size="large" tip="Loading environments..." />
228+
</div>
229+
) : environments.length === 0 && !error ? (
230+
<Empty
231+
description="No environments found"
232+
image={Empty.PRESENTED_IMAGE_SIMPLE}
233+
style={{ padding: '60px 0' }}
234+
/>
235+
) : filteredEnvironments.length === 0 ? (
236+
<Empty
237+
description="No environments match your search"
238+
image={Empty.PRESENTED_IMAGE_SIMPLE}
239+
style={{ padding: '60px 0' }}
240+
/>
241+
) : (
242+
/* Table component */
243+
<EnvironmentsTable
244+
environments={filteredEnvironments}
245+
loading={isLoading}
246+
onRowClick={handleRowClick}
247+
/>
248+
)}
84249

85-
{/* Empty state handling */}
86-
{!isLoading && environments.length === 0 && !error ? (
87-
<Empty
88-
description="No environments found"
89-
image={Empty.PRESENTED_IMAGE_SIMPLE}
90-
/>
91-
) : (
92-
/* Table component */
93-
<EnvironmentsTable
94-
environments={filteredEnvironments}
95-
loading={isLoading}
96-
onRowClick={handleRowClick}
97-
/>
98-
)}
250+
{/* Results counter when searching */}
251+
{searchText && filteredEnvironments.length !== environments.length && (
252+
<div style={{ marginTop: 16, color: '#8c8c8c', textAlign: 'right' }}>
253+
Showing {filteredEnvironments.length} of {environments.length} environments
254+
</div>
255+
)}
256+
</Card>
99257
</div>
100258
);
101259
};

0 commit comments

Comments
 (0)