Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 880a4fb

Browse files
committed
[FIx]: improve UI for environments
1 parent 55ff3e5 commit 880a4fb

File tree

5 files changed

+232
-137
lines changed

5 files changed

+232
-137
lines changed

‎client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
Button,
1111
Tag,
1212
Result,
13+
Row,
14+
Col,
1315
} from "antd";
1416
import {
1517
LinkOutlined,
@@ -21,6 +23,9 @@ import {
2123
CloseCircleOutlined,
2224
ExclamationCircleOutlined,
2325
SyncOutlined,
26+
CloudServerOutlined,
27+
UserOutlined,
28+
SafetyOutlined,
2429
} from "@ant-design/icons";
2530

2631
import { useSingleEnvironmentContext } from "./context/SingleEnvironmentContext";
@@ -31,9 +36,11 @@ import history from "@lowcoder-ee/util/history";
3136
import WorkspacesTab from "./components/WorkspacesTab";
3237
import UserGroupsTab from "./components/UserGroupsTab";
3338
import EnvironmentHeader from "./components/EnvironmentHeader";
39+
import StatsCard from "./components/StatsCard";
3440
import ModernBreadcrumbs from "./components/ModernBreadcrumbs";
3541
import { getEnvironmentTagColor } from "./utils/environmentUtils";
3642
import ErrorComponent from './components/ErrorComponent';
43+
import { Level1SettingPageContent } from "../styled";
3744

3845
/**
3946
* Environment Detail Page Component
@@ -123,19 +130,31 @@ const EnvironmentDetail: React.FC = () => {
123130
);
124131
}
125132

126-
const breadcrumbItems = [
133+
// Stats data for the cards
134+
const statsData = [
127135
{
128-
key: 'environments',
129-
title: (
130-
<span>
131-
<HomeOutlined /> Environments
132-
</span>
133-
),
134-
onClick: () => history.push("/setting/environments")
136+
title: "Type",
137+
value: environment.environmentType || "Unknown",
138+
icon: <CloudServerOutlined />,
139+
color: getEnvironmentTagColor(environment.environmentType)
140+
},
141+
{
142+
title: "Status",
143+
value: environment.isLicensed ? "Licensed" : "Unlicensed",
144+
icon: environment.isLicensed ? <CheckCircleOutlined /> : <CloseCircleOutlined />,
145+
color: environment.isLicensed ? "#52c41a" : "#ff4d4f"
146+
},
147+
{
148+
title: "API Key",
149+
value: environment.environmentApikey ? "Configured" : "Not Set",
150+
icon: <SafetyOutlined />,
151+
color: environment.environmentApikey ? "#1890ff" : "#faad14"
135152
},
136153
{
137-
key: 'currentEnvironment',
138-
title: environment.environmentName
154+
title: "Master Env",
155+
value: environment.isMaster ? "Yes" : "No",
156+
icon: <UserOutlined />,
157+
color: environment.isMaster ? "#722ed1" : "#8c8c8c"
139158
}
140159
];
141160

@@ -161,16 +180,30 @@ const EnvironmentDetail: React.FC = () => {
161180
];
162181

163182
return (
164-
<div
165-
className="environment-detail-container"
166-
style={{ padding: "24px", flex: 1, minWidth: "1000px" }}
167-
>
183+
<Level1SettingPageContent>
184+
{/* Breadcrumbs */}
185+
186+
168187
{/* Environment Header Component */}
169188
<EnvironmentHeader
170189
environment={environment}
171190
onEditClick={handleEditClick}
172191
/>
173192

193+
{/* Stats Cards Row */}
194+
<Row gutter={[16, 16]} style={{ marginBottom: "24px" }}>
195+
{statsData.map((stat, index) => (
196+
<Col xs={24} sm={12} lg={6} key={index}>
197+
<StatsCard
198+
title={stat.title}
199+
value={stat.value}
200+
icon={stat.icon}
201+
color={stat.color}
202+
/>
203+
</Col>
204+
))}
205+
</Row>
206+
174207
{/* Basic Environment Information Card */}
175208
<Card
176209
title="Environment Overview"
@@ -200,13 +233,10 @@ const EnvironmentDetail: React.FC = () => {
200233
"No domain set"
201234
)}
202235
</Descriptions.Item>
203-
<Descriptions.Item label="Environment Type">
204-
<Tag
205-
color={getEnvironmentTagColor(environment.environmentType)}
206-
style={{ borderRadius: '4px' }}
207-
>
208-
{environment.environmentType}
209-
</Tag>
236+
<Descriptions.Item label="Environment ID">
237+
<code style={{ padding: '2px 6px', background: '#f5f5f5', borderRadius: '3px' }}>
238+
{environment.environmentId}
239+
</code>
210240
</Descriptions.Item>
211241
<Descriptions.Item label="License Status">
212242
{(() => {
@@ -224,21 +254,25 @@ const EnvironmentDetail: React.FC = () => {
224254
}
225255
})()}
226256
</Descriptions.Item>
227-
<Descriptions.Item label="API Key Status">
228-
{environment.environmentApikey ? (
229-
<Tag color="green" style={{ borderRadius: '4px' }}>Configured</Tag>
230-
) : (
231-
<Tag color="red" style={{ borderRadius: '4px' }}>Not Configured</Tag>
232-
)}
233-
</Descriptions.Item>
234-
<Descriptions.Item label="Master Environment">
235-
{environment.isMaster ? "Yes" : "No"}
257+
<Descriptions.Item label="Created">
258+
{environment.createdAt ? new Date(environment.createdAt).toLocaleDateString() : "Unknown"}
236259
</Descriptions.Item>
237260
</Descriptions>
238261
</Card>
239262

240-
{/* Modern Breadcrumbs navigation */}
241-
<ModernBreadcrumbs items={breadcrumbItems} />
263+
<ModernBreadcrumbs
264+
items={[
265+
{
266+
key: 'environments',
267+
title: 'Environments',
268+
onClick: () => history.push('/setting/environments')
269+
},
270+
{
271+
key: 'current',
272+
title: environment.environmentName || "Environment Detail"
273+
}
274+
]}
275+
/>
242276

243277
{/* Tabs for Workspaces and User Groups */}
244278
<Tabs
@@ -260,7 +294,7 @@ const EnvironmentDetail: React.FC = () => {
260294
loading={isUpdating}
261295
/>
262296
)}
263-
</div>
297+
</Level1SettingPageContent>
264298
);
265299
};
266300

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

Lines changed: 37 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState, useEffect } from "react";
2-
import { Alert, Empty, Spin, Card } from "antd";
2+
import { Alert, Empty, Spin, Card, Row, Col } from "antd";
33
import { SyncOutlined, CloudServerOutlined } from "@ant-design/icons";
44
import { AddIcon, Search, TacoButton } from "lowcoder-design";
55
import { useHistory } from "react-router-dom";
@@ -9,6 +9,7 @@ import { fetchEnvironments } from "redux/reduxActions/enterpriseActions";
99
import { Environment } from "./types/environment.types";
1010
import EnvironmentsTable from "./components/EnvironmentsTable";
1111
import CreateEnvironmentModal from "./components/CreateEnvironmentModal";
12+
import StatsCard from "./components/StatsCard";
1213
import { buildEnvironmentId } from "@lowcoder-ee/constants/routesURL";
1314
import { createEnvironment } from "./services/environments.service";
1415
import { getEnvironmentTagColor } from "./utils/environmentUtils";
@@ -107,37 +108,6 @@ const EnvironmentsList: React.FC = () => {
107108
return <CloudServerOutlined />;
108109
};
109110

110-
// Stat card component
111-
const StatCard = ({ title, value, color }: { title: string; value: number; color: string }) => (
112-
<Card
113-
style={{
114-
height: '100%',
115-
borderRadius: '4px',
116-
border: '1px solid #f0f0f0'
117-
}}
118-
>
119-
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
120-
<div>
121-
<div style={{ fontSize: '13px', color: '#8c8c8c', marginBottom: '8px' }}>{title}</div>
122-
<div style={{ fontSize: '20px', fontWeight: 500 }}>{value}</div>
123-
</div>
124-
<div style={{
125-
fontSize: '24px',
126-
opacity: 0.8,
127-
color: color,
128-
padding: '8px',
129-
backgroundColor: `${color}15`,
130-
borderRadius: '4px',
131-
display: 'flex',
132-
alignItems: 'center',
133-
justifyContent: 'center'
134-
}}>
135-
{getEnvironmentIcon(title)}
136-
</div>
137-
</div>
138-
</Card>
139-
);
140-
141111
// Filter environments based on search text
142112
const filteredEnvironments = environments.filter((env) => {
143113
const searchLower = searchText.toLowerCase();
@@ -201,75 +171,65 @@ const EnvironmentsList: React.FC = () => {
201171
>
202172
Refresh
203173
</RefreshBtn>
204-
<AddBtn buttonType="primary" onClick={() => setIsCreateModalVisible(true)}>
205-
New Environment
174+
<AddBtn
175+
buttonType="primary"
176+
icon={<AddIcon />}
177+
onClick={() => setIsCreateModalVisible(true)}
178+
>
179+
Add Environment
206180
</AddBtn>
207181
</HeaderWrapper>
208182

209183
<BodyWrapper>
210-
{/* Environment Type Statistics */}
211-
{!isLoading && environments.length > 0 && (
212-
<StatsWrapper>
213-
<div style={{ display: 'flex', gap: '16px', marginBottom: '20px', flexWrap: 'wrap' }}>
214-
{environmentStats.map(([type, count]) => (
215-
<div key={type} style={{ minWidth: '200px', flex: '1' }}>
216-
<StatCard
217-
title={type}
218-
value={count}
219-
color={getEnvironmentTagColor(type.toLowerCase())}
220-
/>
221-
</div>
222-
))}
223-
</div>
224-
</StatsWrapper>
225-
)}
184+
{/* Environment Statistics Cards */}
185+
<StatsWrapper>
186+
<Row gutter={[16, 16]}>
187+
{environmentStats.map(([type, count]) => (
188+
<Col xs={24} sm={12} md={8} lg={6} key={type}>
189+
<StatsCard
190+
title={`${type} Environments`}
191+
value={count}
192+
icon={getEnvironmentIcon(type)}
193+
color={getEnvironmentTagColor(type)}
194+
/>
195+
</Col>
196+
))}
197+
</Row>
198+
</StatsWrapper>
226199

227-
{/* Error handling */}
228200
{error && (
229201
<Alert
230202
message="Error loading environments"
231203
description={error}
232204
type="error"
233205
showIcon
234-
style={{ marginBottom: "16px" }}
206+
style={{ marginBottom: 16 }}
235207
/>
236208
)}
237209

238-
{/* Loading, empty state or table */}
239-
{isLoading ? (
240-
<div style={{ display: 'flex', justifyContent: 'center', padding: '60px 0' }}>
241-
<Spin size="large" />
242-
</div>
243-
) : environments.length === 0 && !error ? (
244-
<Empty
245-
description="No environments found"
246-
image={Empty.PRESENTED_IMAGE_SIMPLE}
247-
style={{ padding: '60px 0' }}
210+
{!isLoading && !error && filteredEnvironments.length === 0 && searchText && (
211+
<Empty
212+
description={`No environments found matching "${searchText}"`}
213+
style={{ margin: "60px 0" }}
248214
/>
249-
) : filteredEnvironments.length === 0 ? (
250-
<Empty
251-
description="No environments match your search"
252-
image={Empty.PRESENTED_IMAGE_SIMPLE}
253-
style={{ padding: '60px 0' }}
215+
)}
216+
217+
{!isLoading && !error && environments.length === 0 && !searchText && (
218+
<Empty
219+
description="No environments found. Create your first environment to get started."
220+
style={{ margin: "60px 0" }}
254221
/>
255-
) : (
256-
/* Table component */
222+
)}
223+
224+
{(filteredEnvironments.length > 0 || isLoading) && (
257225
<EnvironmentsTable
258226
environments={filteredEnvironments}
259227
loading={isLoading}
260228
onRowClick={handleRowClick}
261229
/>
262230
)}
263-
264-
{/* Results counter when searching */}
265-
{searchText && filteredEnvironments.length !== environments.length && (
266-
<div style={{ marginTop: 16, color: '#8c8c8c', textAlign: 'right' }}>
267-
Showing {filteredEnvironments.length} of {environments.length} environments
268-
</div>
269-
)}
270231
</BodyWrapper>
271232

272-
{/* Create Environment Modal */}
273233
<CreateEnvironmentModal
274234
visible={isCreateModalVisible}
275235
onClose={() => setIsCreateModalVisible(false)}

0 commit comments

Comments
 (0)