Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0ee3f1f

Browse files
committed
Add api calls count
1 parent702a961 commit0ee3f1f

File tree

5 files changed

+294
-11
lines changed

5 files changed

+294
-11
lines changed

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

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import {
1010
Button,
1111
Tag,
1212
Result,
13+
Progress,
14+
Statistic,
15+
Row,
16+
Col,
17+
Tooltip,
1318
}from"antd";
1419
import{
1520
LinkOutlined,
@@ -21,6 +26,9 @@ import {
2126
CloseCircleOutlined,
2227
ExclamationCircleOutlined,
2328
SyncOutlined,
29+
ApiOutlined,
30+
UserOutlined,
31+
CrownOutlined,
2432
}from"@ant-design/icons";
2533

2634
import{useSingleEnvironmentContext}from"./context/SingleEnvironmentContext";
@@ -33,6 +41,7 @@ import UserGroupsTab from "./components/UserGroupsTab";
3341
importEnvironmentHeaderfrom"./components/EnvironmentHeader";
3442
importModernBreadcrumbsfrom"./components/ModernBreadcrumbs";
3543
import{getEnvironmentTagColor}from"./utils/environmentUtils";
44+
import{formatAPICalls,getAPICallsStatusColor}from"./services/license.service";
3645
importErrorComponentfrom'./components/ErrorComponent';
3746
const{ TabPane}=Tabs;
3847

@@ -217,6 +226,151 @@ const EnvironmentDetail: React.FC = () => {
217226
</Descriptions>
218227
</Card>
219228

229+
{/* Detailed License Information Card - only show for licensed environments with details */}
230+
{environment.isLicensed&&environment.licenseDetails&&(
231+
<Card
232+
title={
233+
<span>
234+
<CrownOutlinedstyle={{color:'#52c41a',marginRight:'8px'}}/>
235+
License Details
236+
</span>
237+
}
238+
style={{
239+
marginBottom:"24px",
240+
borderRadius:'4px',
241+
border:'1px solid #f0f0f0'
242+
}}
243+
className="license-details-card"
244+
>
245+
<Rowgutter={[24,16]}>
246+
{/* API Calls Status */}
247+
<Colxs={24}sm={12}md={8}>
248+
<Card
249+
size="small"
250+
style={{height:'100%',textAlign:'center'}}
251+
bodyStyle={{padding:'16px'}}
252+
>
253+
<Statistic
254+
title="API Calls Remaining"
255+
value={environment.licenseDetails.remainingAPICalls}
256+
formatter={(value)=>(
257+
<spanstyle={{
258+
color:getAPICallsStatusColor(
259+
environment.licenseDetails?.remainingAPICalls||0,
260+
environment.licenseDetails?.totalAPICallsLimit||0
261+
)
262+
}}>
263+
{value?.toLocaleString()}
264+
</span>
265+
)}
266+
prefix={<ApiOutlined/>}
267+
/>
268+
<divstyle={{marginTop:'12px'}}>
269+
<Progress
270+
percent={100-(environment.licenseDetails.apiCallsUsage||0)}
271+
strokeColor={getAPICallsStatusColor(
272+
environment.licenseDetails.remainingAPICalls,
273+
environment.licenseDetails.totalAPICallsLimit||0
274+
)}
275+
size="small"
276+
showInfo={false}
277+
/>
278+
<divstyle={{
279+
fontSize:'12px',
280+
color:'#8c8c8c',
281+
marginTop:'4px'
282+
}}>
283+
{environment.licenseDetails.apiCallsUsage||0}% used
284+
</div>
285+
</div>
286+
</Card>
287+
</Col>
288+
289+
{/* Total License Limit */}
290+
<Colxs={24}sm={12}md={8}>
291+
<Card
292+
size="small"
293+
style={{height:'100%',textAlign:'center'}}
294+
bodyStyle={{padding:'16px'}}
295+
>
296+
<Statistic
297+
title="Total API Calls Limit"
298+
value={environment.licenseDetails.totalAPICallsLimit}
299+
formatter={(value)=>value?.toLocaleString()}
300+
prefix={<ApiOutlined/>}
301+
/>
302+
<Tag
303+
color="blue"
304+
style={{marginTop:'12px'}}
305+
>
306+
{environment.licenseDetails.eeLicenses.length} License{environment.licenseDetails.eeLicenses.length!==1 ?'s' :''}
307+
</Tag>
308+
</Card>
309+
</Col>
310+
311+
{/* Enterprise Edition Status */}
312+
<Colxs={24}sm={12}md={8}>
313+
<Card
314+
size="small"
315+
style={{height:'100%',textAlign:'center'}}
316+
bodyStyle={{padding:'16px'}}
317+
>
318+
<Statistic
319+
title="Enterprise Edition"
320+
value={environment.licenseDetails.eeActive ?"Active" :"Inactive"}
321+
formatter={(value)=>(
322+
<Tag
323+
color={environment.licenseDetails?.eeActive ?"green" :"red"}
324+
icon={environment.licenseDetails?.eeActive ?<CheckCircleOutlined/> :<CloseCircleOutlined/>}
325+
>
326+
{value}
327+
</Tag>
328+
)}
329+
/>
330+
</Card>
331+
</Col>
332+
</Row>
333+
334+
{/* License Details */}
335+
<divstyle={{marginTop:'24px'}}>
336+
<Typography.Titlelevel={5}style={{marginBottom:'16px'}}>
337+
<UserOutlinedstyle={{marginRight:'8px'}}/>
338+
License Information
339+
</Typography.Title>
340+
341+
<Rowgutter={[16,16]}>
342+
{environment.licenseDetails.eeLicenses.map((license,index)=>(
343+
<Colxs={24}sm={12}md={8}key={license.uuid}>
344+
<Card
345+
size="small"
346+
style={{
347+
border:'1px solid #f0f0f0',
348+
borderRadius:'6px'
349+
}}
350+
bodyStyle={{padding:'12px'}}
351+
>
352+
<divstyle={{marginBottom:'8px'}}>
353+
<strongstyle={{color:'#262626'}}>
354+
{license.customerName}
355+
</strong>
356+
</div>
357+
<divstyle={{fontSize:'12px',color:'#8c8c8c',marginBottom:'8px'}}>
358+
ID:{license.customerId}
359+
</div>
360+
<divstyle={{fontSize:'12px',color:'#8c8c8c',marginBottom:'8px'}}>
361+
UUID:<spanstyle={{fontFamily:'monospace'}}>{license.uuid.substring(0,8)}...</span>
362+
</div>
363+
<Tagcolor="blue">
364+
{license.apiCallsLimit.toLocaleString()} calls
365+
</Tag>
366+
</Card>
367+
</Col>
368+
))}
369+
</Row>
370+
</div>
371+
</Card>
372+
)}
373+
220374
{/* Modern Breadcrumbs navigation */}
221375
<ModernBreadcrumbsitems={breadcrumbItems}/>
222376

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

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
importReactfrom'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

@@ -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+
<divstyle={{marginTop:'8px',padding:'8px',background:'#fafafa',borderRadius:'4px'}}>
275+
<divstyle={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:'6px'}}>
276+
<Texttype="secondary"style={{fontSize:'11px'}}>
277+
<ApiOutlinedstyle={{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+
<divstyle={{
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/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';

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

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
importaxiosfrom'axios';
2-
import{EnvironmentLicense}from'../types/environment.types';
2+
import{EnvironmentLicense,DetailedLicenseInfo}from'../types/environment.types';
33

44
/**
5-
* Checkiflicenseendpoint exists for an environment
5+
* Check licenseand fetch detailed license information for an environment
66
*@param apiServiceUrl - API service URL for the environment
77
*@param apiKey - API key for the environment
8-
*@returns Promise with license information
8+
*@returns Promise with license information including detailed data
99
*/
1010
exportasyncfunctioncheckEnvironmentLicense(
1111
apiServiceUrl:string,
@@ -25,25 +25,93 @@ export async function checkEnvironmentLicense(
2525
headers.Authorization=`Bearer${apiKey}`;
2626
}
2727

28-
//Use GET request to check endpoint existence
29-
awaitaxios.get(
28+
//Fetch detailed license information
29+
constresponse=awaitaxios.get(
3030
`${apiServiceUrl}/api/plugins/enterprise/license`,
3131
{
3232
headers,
3333
timeout:500// Very short timeout for immediate failure when endpoint doesn't exist
3434
}
3535
);
3636

37-
// If we get a successful response, the endpoint exists
37+
// Parse the license response
38+
constlicenseData=response.data;
39+
40+
// Calculate total API calls limit and usage percentage
41+
consttotalAPICallsLimit=licenseData.eeLicenses?.reduce(
42+
(sum:number,license:any)=>sum+(license.apiCallsLimit||0),
43+
0
44+
)||0;
45+
46+
constapiCallsUsage=totalAPICallsLimit>0
47+
?Math.round(((totalAPICallsLimit-licenseData.remainingAPICalls)/totalAPICallsLimit)*100)
48+
:0;
49+
50+
constlicenseDetails:DetailedLicenseInfo={
51+
eeActive:licenseData.eeActive||false,
52+
remainingAPICalls:licenseData.remainingAPICalls||0,
53+
eeLicenses:licenseData.eeLicenses||[],
54+
totalAPICallsLimit,
55+
apiCallsUsage
56+
};
57+
58+
// Determine if license is valid based on enterprise edition status and remaining calls
59+
constisValid=licenseDetails.eeActive&&licenseDetails.remainingAPICalls>0;
60+
3861
return{
39-
isValid:true
62+
isValid,
63+
details:licenseDetails
4064
};
4165

4266
}catch(error){
43-
// Any error means the endpoint doesn't exist or isn't accessible
67+
// Determine the specific error type
68+
leterrorMessage='License not available';
69+
70+
if(axios.isAxiosError(error)){
71+
if(error.code==='ECONNABORTED'){
72+
errorMessage='License check timed out';
73+
}elseif(error.response?.status===404){
74+
errorMessage='License endpoint not found';
75+
}elseif(error.response?.status===401){
76+
errorMessage='Unauthorized - check API key';
77+
}elseif(error.response&&error.response.status>=500){
78+
errorMessage='License server error';
79+
}
80+
}
81+
4482
return{
4583
isValid:false,
46-
error:'License not available'
84+
error:errorMessage
4785
};
4886
}
87+
}
88+
89+
/**
90+
* Format API calls for display
91+
*@param remaining - Remaining API calls
92+
*@param total - Total API calls limit
93+
*@returns Formatted string
94+
*/
95+
exportfunctionformatAPICalls(remaining:number,total:number):string{
96+
constused=total-remaining;
97+
constpercentage=total>0 ?Math.round((used/total)*100) :0;
98+
99+
return`${remaining.toLocaleString()} remaining (${used.toLocaleString()}/${total.toLocaleString()} used,${percentage}%)`;
100+
}
101+
102+
/**
103+
* Get API calls status color based on usage percentage
104+
*@param remainingCalls - Remaining API calls
105+
*@param totalCalls - Total API calls limit
106+
*@returns Color string for UI components
107+
*/
108+
exportfunctiongetAPICallsStatusColor(remainingCalls:number,totalCalls:number):string{
109+
if(totalCalls===0)return'#d9d9d9';// Unknown
110+
111+
constusagePercentage=((totalCalls-remainingCalls)/totalCalls)*100;
112+
113+
if(usagePercentage>=90)return'#ff4d4f';// Red - Critical
114+
if(usagePercentage>=75)return'#faad14';// Orange - Warning
115+
if(usagePercentage>=50)return'#1890ff';// Blue - Moderate
116+
return'#52c41a';// Green - Good
49117
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp