Skip to content

Commit d90330b

Browse files
authored
Merge pull request #1724 from iamfaran/fix/ui-and-deployment-issues
[Fix]: Update more UI Pages for the Environments + Add API Call Count in UI
2 parents 18822d7 + c28c62f commit d90330b

21 files changed

+923
-585
lines changed

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

Lines changed: 239 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import {
1010
Button,
1111
Tag,
1212
Result,
13+
Row,
14+
Col,
15+
Statistic,
16+
Progress,
1317
} from "antd";
1418
import {
1519
LinkOutlined,
@@ -21,6 +25,11 @@ import {
2125
CloseCircleOutlined,
2226
ExclamationCircleOutlined,
2327
SyncOutlined,
28+
CloudServerOutlined,
29+
UserOutlined,
30+
SafetyOutlined,
31+
CrownOutlined,
32+
ApiOutlined,
2433
} from "@ant-design/icons";
2534

2635
import { useSingleEnvironmentContext } from "./context/SingleEnvironmentContext";
@@ -31,10 +40,12 @@ import history from "@lowcoder-ee/util/history";
3140
import WorkspacesTab from "./components/WorkspacesTab";
3241
import UserGroupsTab from "./components/UserGroupsTab";
3342
import EnvironmentHeader from "./components/EnvironmentHeader";
43+
import StatsCard from "./components/StatsCard";
3444
import ModernBreadcrumbs from "./components/ModernBreadcrumbs";
3545
import { getEnvironmentTagColor } from "./utils/environmentUtils";
46+
import { formatAPICalls, getAPICallsStatusColor } from "./services/license.service";
3647
import ErrorComponent from './components/ErrorComponent';
37-
const { TabPane } = Tabs;
48+
import { Level1SettingPageContent } from "../styled";
3849

3950
/**
4051
* Environment Detail Page Component
@@ -124,33 +135,80 @@ const EnvironmentDetail: React.FC = () => {
124135
);
125136
}
126137

127-
const breadcrumbItems = [
138+
// Stats data for the cards
139+
const statsData = [
128140
{
129-
key: 'environments',
130-
title: (
141+
title: "Type",
142+
value: environment.environmentType || "Unknown",
143+
icon: <CloudServerOutlined />,
144+
color: getEnvironmentTagColor(environment.environmentType)
145+
},
146+
{
147+
title: "Status",
148+
value: environment.isLicensed ? "Licensed" : "Unlicensed",
149+
icon: environment.isLicensed ? <CheckCircleOutlined /> : <CloseCircleOutlined />,
150+
color: environment.isLicensed ? "#52c41a" : "#ff4d4f"
151+
},
152+
{
153+
title: "API Key",
154+
value: environment.environmentApikey ? "Configured" : "Not Set",
155+
icon: <SafetyOutlined />,
156+
color: environment.environmentApikey ? "#1890ff" : "#faad14"
157+
},
158+
{
159+
title: "Master Env",
160+
value: environment.isMaster ? "Yes" : "No",
161+
icon: <UserOutlined />,
162+
color: environment.isMaster ? "#722ed1" : "#8c8c8c"
163+
}
164+
];
165+
166+
const tabItems = [
167+
{
168+
key: 'workspaces',
169+
label: (
131170
<span>
132-
<HomeOutlined /> Environments
171+
<AppstoreOutlined /> Workspaces
133172
</span>
134173
),
135-
onClick: () => history.push("/setting/environments")
174+
children: <WorkspacesTab environment={environment} />
136175
},
137176
{
138-
key: 'currentEnvironment',
139-
title: environment.environmentName
177+
key: 'userGroups',
178+
label: (
179+
<span>
180+
<UsergroupAddOutlined /> User Groups
181+
</span>
182+
),
183+
children: <UserGroupsTab environment={environment} />
140184
}
141185
];
142186

143187
return (
144-
<div
145-
className="environment-detail-container"
146-
style={{ padding: "24px", flex: 1, minWidth: "1000px" }}
147-
>
188+
<Level1SettingPageContent style={{ minWidth: "1000px" }}>
189+
{/* Breadcrumbs */}
190+
191+
148192
{/* Environment Header Component */}
149193
<EnvironmentHeader
150194
environment={environment}
151195
onEditClick={handleEditClick}
152196
/>
153197

198+
{/* Stats Cards Row */}
199+
<Row gutter={[16, 16]} style={{ marginBottom: "24px" }}>
200+
{statsData.map((stat, index) => (
201+
<Col xs={24} sm={12} lg={6} key={index}>
202+
<StatsCard
203+
title={stat.title}
204+
value={stat.value}
205+
icon={stat.icon}
206+
color={stat.color}
207+
/>
208+
</Col>
209+
))}
210+
</Row>
211+
154212
{/* Basic Environment Information Card */}
155213
<Card
156214
title="Environment Overview"
@@ -180,13 +238,10 @@ const EnvironmentDetail: React.FC = () => {
180238
"No domain set"
181239
)}
182240
</Descriptions.Item>
183-
<Descriptions.Item label="Environment Type">
184-
<Tag
185-
color={getEnvironmentTagColor(environment.environmentType)}
186-
style={{ borderRadius: '4px' }}
187-
>
188-
{environment.environmentType}
189-
</Tag>
241+
<Descriptions.Item label="Environment ID">
242+
<code style={{ padding: '2px 6px', background: '#f5f5f5', borderRadius: '3px' }}>
243+
{environment.environmentId}
244+
</code>
190245
</Descriptions.Item>
191246
<Descriptions.Item label="License Status">
192247
{(() => {
@@ -196,29 +251,178 @@ const EnvironmentDetail: React.FC = () => {
196251
case 'licensed':
197252
return <Tag icon={<CheckCircleOutlined />} color="green" style={{ borderRadius: '4px' }}>Licensed</Tag>;
198253
case 'unlicensed':
199-
return <Tag icon={<CloseCircleOutlined />} color="red" style={{ borderRadius: '4px' }}>Not Licensed</Tag>;
254+
return <Tag icon={<CloseCircleOutlined />} color="orange" style={{ borderRadius: '4px' }}>License Needed</Tag>;
200255
case 'error':
201-
return <Tag icon={<ExclamationCircleOutlined />} color="orange" style={{ borderRadius: '4px' }}>License Error</Tag>;
256+
return <Tag icon={<ExclamationCircleOutlined />} color="orange" style={{ borderRadius: '4px' }}>Setup Required</Tag>;
202257
default:
203258
return <Tag color="default" style={{ borderRadius: '4px' }}>Unknown</Tag>;
204259
}
205260
})()}
206261
</Descriptions.Item>
207-
<Descriptions.Item label="API Key Status">
208-
{environment.environmentApikey ? (
209-
<Tag color="green" style={{ borderRadius: '4px' }}>Configured</Tag>
210-
) : (
211-
<Tag color="red" style={{ borderRadius: '4px' }}>Not Configured</Tag>
212-
)}
213-
</Descriptions.Item>
214-
<Descriptions.Item label="Master Environment">
215-
{environment.isMaster ? "Yes" : "No"}
262+
<Descriptions.Item label="Created">
263+
{environment.createdAt ? new Date(environment.createdAt).toLocaleDateString() : "Unknown"}
216264
</Descriptions.Item>
217265
</Descriptions>
218266
</Card>
219267

220-
{/* Modern Breadcrumbs navigation */}
221-
<ModernBreadcrumbs items={breadcrumbItems} />
268+
<ModernBreadcrumbs
269+
items={[
270+
{
271+
key: 'environments',
272+
title: 'Environments',
273+
onClick: () => history.push('/setting/environments')
274+
},
275+
{
276+
key: 'current',
277+
title: environment.environmentName || "Environment Detail"
278+
}
279+
]}
280+
/>
281+
{/* Detailed License Information Card - only show for licensed environments with details */}
282+
{environment.isLicensed && environment.licenseDetails && (
283+
<Card
284+
title={
285+
<span>
286+
<CrownOutlined style={{ color: '#52c41a', marginRight: '8px' }} />
287+
License Details
288+
</span>
289+
}
290+
style={{
291+
marginBottom: "24px",
292+
borderRadius: '4px',
293+
border: '1px solid #f0f0f0'
294+
}}
295+
className="license-details-card"
296+
>
297+
<Row gutter={[24, 16]}>
298+
{/* API Calls Status */}
299+
<Col xs={24} sm={12} md={8}>
300+
<Card
301+
size="small"
302+
style={{ height: '100%', textAlign: 'center' }}
303+
styles={{ body: { padding: '16px' } }}
304+
>
305+
<Statistic
306+
title="API Calls Remaining"
307+
value={environment.licenseDetails.remainingAPICalls}
308+
formatter={(value) => (
309+
<span style={{
310+
color: getAPICallsStatusColor(
311+
environment.licenseDetails?.remainingAPICalls || 0,
312+
environment.licenseDetails?.totalAPICallsLimit || 0
313+
)
314+
}}>
315+
{value?.toLocaleString()}
316+
</span>
317+
)}
318+
prefix={<ApiOutlined />}
319+
/>
320+
<div style={{ marginTop: '12px' }}>
321+
<Progress
322+
percent={environment.licenseDetails.apiCallsUsage || 0}
323+
strokeColor={getAPICallsStatusColor(
324+
environment.licenseDetails.remainingAPICalls,
325+
environment.licenseDetails.totalAPICallsLimit || 0
326+
)}
327+
size="small"
328+
showInfo={false}
329+
/>
330+
<div style={{
331+
fontSize: '12px',
332+
color: '#8c8c8c',
333+
marginTop: '4px'
334+
}}>
335+
{environment.licenseDetails.apiCallsUsage || 0}% used
336+
</div>
337+
</div>
338+
</Card>
339+
</Col>
340+
341+
{/* Total License Limit */}
342+
<Col xs={24} sm={12} md={8}>
343+
<Card
344+
size="small"
345+
style={{ height: '100%', textAlign: 'center' }}
346+
styles={{ body: { padding: '16px' } }}
347+
>
348+
<Statistic
349+
title="Total API Calls Limit"
350+
value={environment.licenseDetails.totalAPICallsLimit}
351+
formatter={(value) => value?.toLocaleString()}
352+
prefix={<ApiOutlined />}
353+
/>
354+
<Tag
355+
color="blue"
356+
style={{ marginTop: '12px' }}
357+
>
358+
{environment.licenseDetails.eeLicenses.length} License{environment.licenseDetails.eeLicenses.length !== 1 ? 's' : ''}
359+
</Tag>
360+
</Card>
361+
</Col>
362+
363+
{/* Enterprise Edition Status */}
364+
<Col xs={24} sm={12} md={8}>
365+
<Card
366+
size="small"
367+
style={{ height: '100%', textAlign: 'center' }}
368+
styles={{ body: { padding: '16px' } }}
369+
>
370+
<Statistic
371+
title="Enterprise Edition"
372+
value={environment.licenseDetails.eeActive ? "Active" : "Inactive"}
373+
formatter={(value) => (
374+
<Tag
375+
color={environment.licenseDetails?.eeActive ? "green" : "red"}
376+
icon={environment.licenseDetails?.eeActive ? <CheckCircleOutlined /> : <CloseCircleOutlined />}
377+
>
378+
{value}
379+
</Tag>
380+
)}
381+
/>
382+
</Card>
383+
</Col>
384+
</Row>
385+
386+
{/* License Details */}
387+
<div style={{ marginTop: '24px' }}>
388+
<Typography.Title level={5} style={{ marginBottom: '16px' }}>
389+
<UserOutlined style={{ marginRight: '8px' }} />
390+
License Information
391+
</Typography.Title>
392+
393+
<Row gutter={[16, 16]}>
394+
{environment.licenseDetails.eeLicenses.map((license, index) => (
395+
<Col xs={24} sm={12} md={8} key={license.uuid}>
396+
<Card
397+
size="small"
398+
style={{
399+
border: '1px solid #f0f0f0',
400+
borderRadius: '6px'
401+
}}
402+
styles={{ body: { padding: '12px' } }}
403+
>
404+
<div style={{ marginBottom: '8px' }}>
405+
<strong style={{ color: '#262626' }}>
406+
{license.customerName}
407+
</strong>
408+
</div>
409+
<div style={{ fontSize: '12px', color: '#8c8c8c', marginBottom: '8px' }}>
410+
ID: {license.customerId}
411+
</div>
412+
<div style={{ fontSize: '12px', color: '#8c8c8c', marginBottom: '8px' }}>
413+
UUID: <span style={{ fontFamily: 'monospace' }}>{license.uuid.substring(0, 8)}...</span>
414+
</div>
415+
<Tag color="blue">
416+
{license.apiCallsLimit.toLocaleString()} calls
417+
</Tag>
418+
</Card>
419+
</Col>
420+
))}
421+
</Row>
422+
</div>
423+
</Card>
424+
)}
425+
222426

223427
{/* Tabs for Workspaces and User Groups */}
224428
<Tabs
@@ -227,29 +431,8 @@ const EnvironmentDetail: React.FC = () => {
227431
onChange={setActiveTab}
228432
className="modern-tabs"
229433
type="line"
230-
>
231-
<TabPane
232-
tab={
233-
<span>
234-
<AppstoreOutlined /> Workspaces
235-
</span>
236-
}
237-
key="workspaces"
238-
>
239-
<WorkspacesTab environment={environment} />
240-
</TabPane>
241-
242-
<TabPane
243-
tab={
244-
<span>
245-
<UsergroupAddOutlined /> User Groups
246-
</span>
247-
}
248-
key="userGroups"
249-
>
250-
<UserGroupsTab environment={environment} />
251-
</TabPane>
252-
</Tabs>
434+
items={tabItems}
435+
/>
253436

254437
{/* Edit Environment Modal */}
255438
{environment && (
@@ -261,7 +444,7 @@ const EnvironmentDetail: React.FC = () => {
261444
loading={isUpdating}
262445
/>
263446
)}
264-
</div>
447+
</Level1SettingPageContent>
265448
);
266449
};
267450

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy