Skip to content

Commit ed8459b

Browse files
committed
Merge UI, deploy endpoints, Add API count and update license messages
2 parents 2714dde + 2252d2c commit ed8459b

File tree

8 files changed

+322
-45
lines changed

8 files changed

+322
-45
lines changed

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

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
Result,
1313
Row,
1414
Col,
15+
Statistic,
16+
Progress,
1517
} from "antd";
1618
import {
1719
LinkOutlined,
@@ -26,6 +28,8 @@ import {
2628
CloudServerOutlined,
2729
UserOutlined,
2830
SafetyOutlined,
31+
CrownOutlined,
32+
ApiOutlined,
2933
} from "@ant-design/icons";
3034

3135
import { useSingleEnvironmentContext } from "./context/SingleEnvironmentContext";
@@ -39,6 +43,7 @@ import EnvironmentHeader from "./components/EnvironmentHeader";
3943
import StatsCard from "./components/StatsCard";
4044
import ModernBreadcrumbs from "./components/ModernBreadcrumbs";
4145
import { getEnvironmentTagColor } from "./utils/environmentUtils";
46+
import { formatAPICalls, getAPICallsStatusColor } from "./services/license.service";
4247
import ErrorComponent from './components/ErrorComponent';
4348
import { Level1SettingPageContent } from "../styled";
4449

@@ -246,9 +251,9 @@ const EnvironmentDetail: React.FC = () => {
246251
case 'licensed':
247252
return <Tag icon={<CheckCircleOutlined />} color="green" style={{ borderRadius: '4px' }}>Licensed</Tag>;
248253
case 'unlicensed':
249-
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>;
250255
case 'error':
251-
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>;
252257
default:
253258
return <Tag color="default" style={{ borderRadius: '4px' }}>Unknown</Tag>;
254259
}
@@ -273,6 +278,151 @@ const EnvironmentDetail: React.FC = () => {
273278
}
274279
]}
275280
/>
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+
bodyStyle={{ 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={100 - (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+
bodyStyle={{ 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+
bodyStyle={{ 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+
bodyStyle={{ 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+
276426

277427
{/* Tabs for Workspaces and User Groups */}
278428
<Tabs

client/packages/lowcoder/src/pages/setting/environments/components/CreateEnvironmentModal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,9 @@ const CreateEnvironmentModal: React.FC<CreateEnvironmentModalProps> = ({
192192
</Form.Item>
193193

194194
<Alert
195-
message="License Information"
196-
description="After creating the environment, the system will automatically check the license status. Make sure the API service URL and API key are correctly configured for license validation."
197-
type="info"
195+
message="Configuration Requirements"
196+
description="Ensure that the API Service URL is configured and correct, the API key is valid, and for license verification make sure you have both the license and plugin properly installed."
197+
type="warning"
198198
showIcon
199199
style={{ marginTop: '16px' }}
200200
/>

client/packages/lowcoder/src/pages/setting/environments/components/EditEnvironmentModal.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState, useEffect } from 'react';
2-
import { Modal, Form, Input, Select, Switch, Button, Tooltip } from 'antd';
2+
import { Modal, Form, Input, Select, Switch, Button, Alert, Tooltip } from 'antd';
33
import { useSelector } from 'react-redux';
44
import { selectMasterEnvironment, selectHasMasterEnvironment } from 'redux/selectors/enterpriseSelectors';
55
import { Environment } from '../types/environment.types';
@@ -191,7 +191,13 @@ const EditEnvironmentModal: React.FC<EditEnvironmentModalProps> = ({
191191
</div>
192192
</Form.Item>
193193

194-
194+
<Alert
195+
message="Configuration Requirements"
196+
description="Ensure that the API Service URL is configured and correct, the API key is valid, and for license verification make sure you have both the license and plugin properly installed."
197+
type="warning"
198+
showIcon
199+
style={{ marginTop: '16px' }}
200+
/>
195201
</Form>
196202
</Modal>
197203
);

client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React from 'react';
2-
import { Table, Tag, Button, Tooltip, Space, Card, Row, Col, Typography, Avatar, Spin, Alert } from 'antd';
3-
import { EditOutlined, AuditOutlined, LinkOutlined, EnvironmentOutlined, StarFilled, CloudServerOutlined, CheckCircleOutlined, CloseCircleOutlined, ExclamationCircleOutlined, SyncOutlined } from '@ant-design/icons';
2+
import { Table, Tag, Button, Tooltip, Space, Card, Row, Col, Typography, Avatar, Spin, Alert, Progress } from 'antd';
3+
import { EditOutlined, AuditOutlined, LinkOutlined, EnvironmentOutlined, StarFilled, CloudServerOutlined, CheckCircleOutlined, CloseCircleOutlined, ExclamationCircleOutlined, SyncOutlined, ApiOutlined } from '@ant-design/icons';
44
import { Environment } from '../types/environment.types';
55
import { getEnvironmentTagColor, formatEnvironmentType } from '../utils/environmentUtils';
6+
import { getAPICallsStatusColor } from '../services/license.service';
67

78
const { Text, Title } = Typography;
89

@@ -54,29 +55,29 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({
5455
case 'checking':
5556
return {
5657
icon: <SyncOutlined spin />,
57-
color: '#1890ff',
58+
color: '#40a9ff',
5859
text: 'Checking...',
5960
status: 'processing' as const
6061
};
6162
case 'licensed':
6263
return {
6364
icon: <CheckCircleOutlined />,
64-
color: '#52c41a',
65+
color: '#73d13d',
6566
text: 'Licensed',
6667
status: 'success' as const
6768
};
6869
case 'unlicensed':
6970
return {
7071
icon: <CloseCircleOutlined />,
71-
color: '#ff4d4f',
72-
text: 'Not Licensed',
73-
status: 'error' as const
72+
color: '#ff7875',
73+
text: 'License Required',
74+
status: 'warning' as const
7475
};
7576
case 'error':
7677
return {
7778
icon: <ExclamationCircleOutlined />,
78-
color: '#faad14',
79-
text: 'License Error',
79+
color: '#ffc53d',
80+
text: 'Setup Required',
8081
status: 'warning' as const
8182
};
8283
default:
@@ -179,8 +180,8 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({
179180
<Tag
180181
icon={licenseDisplay.icon}
181182
color={licenseDisplay.status === 'success' ? 'green' :
182-
licenseDisplay.status === 'error' ? 'red' :
183-
licenseDisplay.status === 'warning' ? 'orange' : 'blue'}
183+
licenseDisplay.status === 'warning' ? 'orange' :
184+
licenseDisplay.status === 'processing' ? 'blue' : 'default'}
184185
style={{ fontSize: '11px', borderRadius: '4px' }}
185186
>
186187
{licenseDisplay.text}
@@ -267,6 +268,38 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({
267268
</Text>
268269
</div>
269270
</div>
271+
272+
{/* API Calls Information - show if license details are available */}
273+
{env.licenseDetails && (
274+
<div style={{ marginTop: '8px', padding: '8px', background: '#fafafa', borderRadius: '4px' }}>
275+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '6px' }}>
276+
<Text type="secondary" style={{ fontSize: '11px' }}>
277+
<ApiOutlined style={{ marginRight: '4px' }} />
278+
API Calls
279+
</Text>
280+
281+
</div>
282+
<Progress
283+
percent={100 - (env.licenseDetails.apiCallsUsage || 0)}
284+
strokeColor={getAPICallsStatusColor(
285+
env.licenseDetails.remainingAPICalls,
286+
env.licenseDetails.totalAPICallsLimit || 0
287+
)}
288+
size="small"
289+
showInfo={false}
290+
strokeWidth={4}
291+
/>
292+
<div style={{
293+
display: 'flex',
294+
justifyContent: 'space-between',
295+
marginTop: '4px',
296+
fontSize: '10px',
297+
color: '#8c8c8c'
298+
}}>
299+
<span>{env.licenseDetails.apiCallsUsage || 0}% used</span>
300+
</div>
301+
</div>
302+
)}
270303
</div>
271304
</div>
272305
</Card>

client/packages/lowcoder/src/pages/setting/environments/components/UnlicensedEnvironmentView.tsx

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,37 +36,29 @@ const UnlicensedEnvironmentView: React.FC<UnlicensedEnvironmentViewProps> = ({
3636
const getLicenseIcon = () => {
3737
switch (environment.licenseStatus) {
3838
case 'unlicensed':
39-
return <CloseCircleOutlined style={{ fontSize: '48px', color: '#ff4d4f' }} />;
39+
return <CloseCircleOutlined style={{ fontSize: '48px', color: '#ff7875' }} />;
4040
case 'error':
41-
return <ExclamationCircleOutlined style={{ fontSize: '48px', color: '#faad14' }} />;
41+
return <ExclamationCircleOutlined style={{ fontSize: '48px', color: '#ffc53d' }} />;
4242
default:
43-
return <WarningOutlined style={{ fontSize: '48px', color: '#ff4d4f' }} />;
43+
return <WarningOutlined style={{ fontSize: '48px', color: '#ff7875' }} />;
4444
}
4545
};
4646

4747
const getLicenseTitle = () => {
48-
switch (environment.licenseStatus) {
49-
case 'unlicensed':
50-
return 'Environment Not Licensed';
51-
case 'error':
52-
return 'License Configuration Error';
53-
default:
54-
return 'License Issue';
55-
}
56-
};
48+
return environment.licenseError;
49+
}
50+
51+
5752

5853
const getLicenseDescription = () => {
59-
if (environment.licenseError) {
60-
return environment.licenseError;
61-
}
6254

6355
switch (environment.licenseStatus) {
6456
case 'unlicensed':
65-
return 'This environment requires a valid license to access its features and functionality.';
57+
return 'This environment needs a valid license to unlock its full capabilities and features. Please make sure your API Service URL is correctly configured and Plugin is installed.';
6658
case 'error':
67-
return 'There was an error validating the license for this environment. Please check the configuration.';
59+
return 'We encountered an issue while checking the license. Please review the configuration settings.';
6860
default:
69-
return 'This environment has license-related issues that need to be resolved.';
61+
return 'This environment requires license configuration to proceed.';
7062
}
7163
};
7264

client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export async function getEnvironmentById(id: string): Promise<Environment> {
136136
envWithLicense.isLicensed = licenseInfo.isValid;
137137
envWithLicense.licenseStatus = licenseInfo.isValid ? 'licensed' : 'unlicensed';
138138
envWithLicense.licenseError = licenseInfo.error;
139+
envWithLicense.licenseDetails = licenseInfo.details;
139140
} else {
140141
envWithLicense.isLicensed = false;
141142
envWithLicense.licenseStatus = 'error';
@@ -556,6 +557,7 @@ export async function getEnvironmentsWithLicenseStatus(): Promise<Environment[]>
556557
envWithLicense.isLicensed = licenseInfo.isValid;
557558
envWithLicense.licenseStatus = licenseInfo.isValid ? 'licensed' : 'unlicensed';
558559
envWithLicense.licenseError = licenseInfo.error;
560+
envWithLicense.licenseDetails = licenseInfo.details;
559561
} else {
560562
envWithLicense.isLicensed = false;
561563
envWithLicense.licenseStatus = 'error';

0 commit comments

Comments
 (0)