Skip to content

Commit 349fdf1

Browse files
committed
Add Env Listing Page Structure
1 parent a2e5251 commit 349fdf1

File tree

5 files changed

+261
-4
lines changed

5 files changed

+261
-4
lines changed
Lines changed: 136 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,136 @@
1-
export function Environments() {
2-
return <></>;
3-
}
1+
import React, { useState } from 'react';
2+
import { Table, Typography, Alert, Input, Button, Space, Empty } from 'antd';
3+
import { SearchOutlined, ReloadOutlined } from '@ant-design/icons';
4+
import { useHistory } from 'react-router-dom';
5+
import { useEnvironments } from './hooks/useEnvironments';
6+
import { Environment } from './types/environment.types';
7+
8+
const { Title } = Typography;
9+
10+
/**
11+
* Environment Listing Page Component
12+
* Displays a basic table of environments
13+
*/
14+
const Environments: React.FC = () => {
15+
// Use our custom hook to get environments data and states
16+
const { environments, loading, error, refresh } = useEnvironments();
17+
18+
// State for search input
19+
const [searchText, setSearchText] = useState('');
20+
21+
// Hook for navigation (using history instead of navigate)
22+
const history = useHistory();
23+
24+
// Filter environments based on search text
25+
const filteredEnvironments = environments.filter(env => {
26+
const searchLower = searchText.toLowerCase();
27+
return (
28+
(env.environmentName || '').toLowerCase().includes(searchLower) ||
29+
(env.environmentFrontendUrl || '').toLowerCase().includes(searchLower) ||
30+
env.environmentId.toLowerCase().includes(searchLower) ||
31+
env.environmentType.toLowerCase().includes(searchLower)
32+
);
33+
});
34+
35+
// Define table columns - updated to match the actual data structure
36+
const columns = [
37+
{
38+
title: 'Name',
39+
dataIndex: 'environmentName',
40+
key: 'environmentName',
41+
render: (name: string) => name || 'Unnamed Environment',
42+
},
43+
{
44+
title: 'Domain',
45+
dataIndex: 'environmentFrontendUrl',
46+
key: 'environmentFrontendUrl',
47+
render: (url: string) => url || 'No URL',
48+
},
49+
{
50+
title: 'ID',
51+
dataIndex: 'environmentId',
52+
key: 'environmentId',
53+
},
54+
{
55+
title: 'Stage',
56+
dataIndex: 'environmentType',
57+
key: 'environmentType',
58+
},
59+
{
60+
title: 'Master',
61+
dataIndex: 'isMaster',
62+
key: 'isMaster',
63+
render: (isMaster: boolean) => isMaster ? 'Yes' : 'No',
64+
},
65+
];
66+
67+
// Handle row click to navigate to environment detail
68+
const handleRowClick = (record: Environment) => {
69+
history.push(`/home/settings/environments/${record.environmentId}`);
70+
};
71+
72+
return (
73+
<div className="environments-container" style={{ padding: '24px' }}>
74+
{/* Header section with title and controls */}
75+
<div className="environments-header" style={{
76+
marginBottom: '24px',
77+
display: 'flex',
78+
justifyContent: 'space-between',
79+
alignItems: 'center'
80+
}}>
81+
<Title level={3}>Environments</Title>
82+
<Space>
83+
<Input
84+
placeholder="Search environments"
85+
value={searchText}
86+
onChange={e => setSearchText(e.target.value)}
87+
style={{ width: 250 }}
88+
prefix={<SearchOutlined />}
89+
allowClear
90+
/>
91+
<Button
92+
icon={<ReloadOutlined />}
93+
onClick={refresh}
94+
loading={loading}
95+
>
96+
Refresh
97+
</Button>
98+
</Space>
99+
</div>
100+
101+
{/* Error handling */}
102+
{error && (
103+
<Alert
104+
message="Error loading environments"
105+
description={error}
106+
type="error"
107+
showIcon
108+
style={{ marginBottom: '24px' }}
109+
/>
110+
)}
111+
112+
{/* Empty state handling */}
113+
{!loading && environments.length === 0 && !error ? (
114+
<Empty
115+
description="No environments found"
116+
image={Empty.PRESENTED_IMAGE_SIMPLE}
117+
/>
118+
) : (
119+
/* Table component */
120+
<Table
121+
dataSource={filteredEnvironments}
122+
columns={columns}
123+
rowKey="environmentId"
124+
loading={loading}
125+
pagination={{ pageSize: 10 }}
126+
onRow={(record) => ({
127+
onClick: () => handleRowClick(record),
128+
style: { cursor: 'pointer' }
129+
})}
130+
/>
131+
)}
132+
</div>
133+
);
134+
};
135+
136+
export default Environments;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { useState, useEffect, useCallback } from 'react';
2+
import { Environment } from '../types/environment.types';
3+
import { getEnvironments } from '../services/environments.service';
4+
5+
/**
6+
* Interface for the state managed by this hook
7+
*/
8+
interface EnvironmentsState {
9+
environments: Environment[];
10+
loading: boolean;
11+
error: string | null;
12+
}
13+
14+
/**
15+
* Custom hook for fetching and managing environments data
16+
* @returns Object containing environments data, loading state, error state, and refresh function
17+
*/
18+
export const useEnvironments = () => {
19+
// Initialize state with loading true
20+
const [state, setState] = useState<EnvironmentsState>({
21+
environments: [],
22+
loading: true,
23+
error: null,
24+
});
25+
26+
/**
27+
* Function to fetch environments from the API
28+
*/
29+
const fetchEnvironments = useCallback(async () => {
30+
// Set loading state
31+
setState(prev => ({ ...prev, loading: true, error: null }));
32+
33+
try {
34+
// Call the API service
35+
const environments = await getEnvironments();
36+
37+
// Update state with fetched data
38+
setState({
39+
environments,
40+
loading: false,
41+
error: null,
42+
});
43+
} catch (error) {
44+
// Handle error state
45+
setState(prev => ({
46+
...prev,
47+
loading: false,
48+
error: error instanceof Error ? error.message : 'An unknown error occurred',
49+
}));
50+
}
51+
}, []);
52+
53+
// Fetch environments on component mount
54+
useEffect(() => {
55+
fetchEnvironments();
56+
}, [fetchEnvironments]);
57+
58+
// Return state values and refresh function
59+
return {
60+
environments: state.environments,
61+
loading: state.loading,
62+
error: state.error,
63+
refresh: fetchEnvironments
64+
};
65+
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import axios from 'axios';
2+
import { message } from 'antd';
3+
import { Environment } from '../types/environment.types';
4+
5+
/**
6+
* Fetch all environments
7+
* @returns Promise with environments data
8+
*/
9+
export async function getEnvironments(): Promise<Environment[]> {
10+
try {
11+
// The response contains the data array directly in response.data
12+
const response = await axios.get('/api/plugins/enterprise/environments/list');
13+
14+
// Return the data array directly from response.data
15+
return response.data || [];
16+
} catch (error) {
17+
const errorMessage = error instanceof Error ? error.message : 'Failed to fetch environments';
18+
message.error(errorMessage);
19+
throw error;
20+
}
21+
}
22+
23+
/**
24+
* Fetch a single environment by ID
25+
* @param id Environment ID
26+
* @returns Promise with environment data
27+
*/
28+
export async function getEnvironmentById(id: string): Promise<Environment> {
29+
try {
30+
const response = await axios.get(`/api/plugins/enterprise/environments/${id}`);
31+
32+
if (!response.data) {
33+
throw new Error('Failed to fetch environment');
34+
}
35+
36+
return response.data;
37+
} catch (error) {
38+
const errorMessage = error instanceof Error ? error.message : 'Failed to fetch environment';
39+
message.error(errorMessage);
40+
throw error;
41+
}
42+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* Interface representing an Environment entity
3+
*/
4+
export interface Environment {
5+
environmentId: string;
6+
environmentName?: string;
7+
environmentDescription?: string;
8+
environmentIcon?: string;
9+
environmentType: string;
10+
environmentApiServiceUrl?: string;
11+
environmentNodeServiceUrl?: string;
12+
environmentFrontendUrl?: string;
13+
environmentApikey: string;
14+
isMaster: boolean;
15+
createdAt: string;
16+
updatedAt: string;
17+
}

client/packages/lowcoder/src/pages/setting/settingHome.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { getUser } from "redux/selectors/usersSelectors";
2525
import history from "util/history";
2626
import { useParams } from "react-router-dom";
2727
import { BrandingSetting } from "@lowcoder-ee/pages/setting/branding/BrandingSetting";
28-
import { Environments } from "@lowcoder-ee/pages/setting/environments/Environments";
28+
import Environments from "@lowcoder-ee/pages/setting/environments/Environments";
2929
import { AppUsage } from "@lowcoder-ee/pages/setting/appUsage";
3030
import { AuditLog } from "@lowcoder-ee/pages/setting/audit";
3131
import { IdSourceHome } from "@lowcoder-ee/pages/setting/idSource";

0 commit comments

Comments
 (0)