Skip to content

Commit d5035d6

Browse files
committed
Test update environment
1 parent 5f393b0 commit d5035d6

File tree

5 files changed

+312
-7
lines changed

5 files changed

+312
-7
lines changed

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

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useEnvironmentContext } from "./context/EnvironmentContext";
66
import { Environment } from "./types/environment.types";
77
import EnvironmentsTable from "./components/EnvironmentsTable";
88
import { buildEnvironmentId } from "@lowcoder-ee/constants/routesURL";
9+
import EditEnvironmentModal from "./components/EditEnvironmentModal";
910

1011
const { Title } = Typography;
1112

@@ -15,7 +16,19 @@ const { Title } = Typography;
1516
*/
1617
const EnvironmentsList: React.FC = () => {
1718
// Use the shared context instead of a local hook
18-
const { environments, isLoadingEnvironments, error, refreshEnvironments } = useEnvironmentContext();
19+
const {
20+
environments,
21+
isLoadingEnvironments,
22+
error,
23+
refreshEnvironments,
24+
updateEnvironmentData
25+
} = useEnvironmentContext();
26+
27+
// State for edit modal
28+
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
29+
const [selectedEnvironment, setSelectedEnvironment] = useState<Environment | null>(null);
30+
const [isUpdating, setIsUpdating] = useState(false);
31+
1932

2033
// State for search input
2134
const [searchText, setSearchText] = useState("");
@@ -39,6 +52,33 @@ const EnvironmentsList: React.FC = () => {
3952
history.push(buildEnvironmentId(record.environmentId));
4053
};
4154

55+
56+
// Handle edit button click
57+
const handleEditClick = (environment: Environment) => {
58+
setSelectedEnvironment(environment);
59+
setIsEditModalVisible(true);
60+
};
61+
62+
// Handle modal close
63+
const handleCloseModal = () => {
64+
setIsEditModalVisible(false);
65+
setSelectedEnvironment(null);
66+
};
67+
68+
// Handle save environment
69+
const handleSaveEnvironment = async (environmentId: string, data: Partial<Environment>) => {
70+
setIsUpdating(true);
71+
try {
72+
// Use the context function to update the environment
73+
// This will automatically update both the environments list and the detail view
74+
await updateEnvironmentData(environmentId, data);
75+
} catch (error) {
76+
console.error('Failed to update environment:', error);
77+
} finally {
78+
setIsUpdating(false);
79+
}
80+
};
81+
4282
return (
4383
<div className="environments-container" style={{ padding: "24px" }}>
4484
{/* Header section with title and controls */}
@@ -94,8 +134,18 @@ const EnvironmentsList: React.FC = () => {
94134
environments={filteredEnvironments}
95135
loading={isLoadingEnvironments}
96136
onRowClick={handleRowClick}
137+
onEditClick={handleEditClick}
97138
/>
98139
)}
140+
141+
{/* Edit Environment Modal */}
142+
<EditEnvironmentModal
143+
visible={isEditModalVisible}
144+
environment={selectedEnvironment}
145+
onClose={handleCloseModal}
146+
onSave={handleSaveEnvironment}
147+
loading={isUpdating}
148+
/>
99149
</div>
100150
);
101151
};
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import React, { useState, useEffect } from 'react';
2+
import { Modal, Form, Input, Select, Switch, Button, message } from 'antd';
3+
import { Environment } from '../types/environment.types';
4+
5+
const { Option } = Select;
6+
7+
interface EditEnvironmentModalProps {
8+
visible: boolean;
9+
environment: Environment | null;
10+
onClose: () => void;
11+
onSave: (environmentId: string, data: Partial<Environment>) => Promise<void>;
12+
loading?: boolean;
13+
}
14+
15+
const EditEnvironmentModal: React.FC<EditEnvironmentModalProps> = ({
16+
visible,
17+
environment,
18+
onClose,
19+
onSave,
20+
loading = false
21+
}) => {
22+
const [form] = Form.useForm();
23+
const [submitLoading, setSubmitLoading] = useState(false);
24+
25+
// Initialize form with environment data when it changes
26+
useEffect(() => {
27+
if (environment) {
28+
form.setFieldsValue({
29+
environmentName: environment.environmentName || '',
30+
environmentDescription: environment.environmentDescription || '',
31+
environmentType: environment.environmentType,
32+
environmentApiServiceUrl: environment.environmentApiServiceUrl || '',
33+
environmentFrontendUrl: environment.environmentFrontendUrl || '',
34+
environmentNodeServiceUrl: environment.environmentNodeServiceUrl || '',
35+
environmentApikey: environment.environmentApikey || '',
36+
isMaster: environment.isMaster
37+
});
38+
}
39+
}, [environment, form]);
40+
41+
const handleSubmit = async () => {
42+
if (!environment) return;
43+
44+
try {
45+
const values = await form.validateFields();
46+
setSubmitLoading(true);
47+
48+
await onSave(environment.environmentId, values);
49+
onClose();
50+
} catch (error) {
51+
if (error instanceof Error) {
52+
console.error("Form validation or submission error:", error);
53+
}
54+
} finally {
55+
setSubmitLoading(false);
56+
}
57+
};
58+
59+
return (
60+
<Modal
61+
title="Edit Environment"
62+
open={visible}
63+
onCancel={onClose}
64+
maskClosable={false}
65+
destroyOnClose={true}
66+
footer={[
67+
<Button key="back" onClick={onClose}>
68+
Cancel
69+
</Button>,
70+
<Button
71+
key="submit"
72+
type="primary"
73+
loading={loading || submitLoading}
74+
onClick={handleSubmit}
75+
>
76+
Save Changes
77+
</Button>
78+
]}
79+
>
80+
<Form
81+
form={form}
82+
layout="vertical"
83+
name="edit_environment_form"
84+
>
85+
<Form.Item
86+
name="environmentName"
87+
label="Environment Name"
88+
rules={[{ required: true, message: 'Please enter a name' }]}
89+
>
90+
<Input placeholder="Enter environment name" />
91+
</Form.Item>
92+
93+
<Form.Item
94+
name="environmentDescription"
95+
label="Description"
96+
>
97+
<Input.TextArea
98+
placeholder="Enter description"
99+
rows={3}
100+
/>
101+
</Form.Item>
102+
103+
<Form.Item
104+
name="environmentType"
105+
label="Stage"
106+
rules={[{ required: true, message: 'Please select a stage' }]}
107+
>
108+
<Select placeholder="Select stage">
109+
<Option value="DEV">Development (DEV)</Option>
110+
<Option value="TEST">Testing (TEST)</Option>
111+
<Option value="PREPROD">Pre-Production (PREPROD)</Option>
112+
<Option value="PROD">Production (PROD)</Option>
113+
</Select>
114+
</Form.Item>
115+
116+
<Form.Item
117+
name="environmentFrontendUrl"
118+
label="Frontend URL"
119+
>
120+
<Input placeholder="https://example.com" />
121+
</Form.Item>
122+
123+
<Form.Item
124+
name="environmentApiServiceUrl"
125+
label="API Service URL"
126+
>
127+
<Input placeholder="https://api.example.com" />
128+
</Form.Item>
129+
130+
<Form.Item
131+
name="environmentNodeServiceUrl"
132+
label="Node Service URL"
133+
>
134+
<Input placeholder="https://node.example.com" />
135+
</Form.Item>
136+
137+
<Form.Item
138+
name="environmentApikey"
139+
label="API Key"
140+
>
141+
<Input.TextArea
142+
placeholder="Enter API key"
143+
rows={2}
144+
/>
145+
</Form.Item>
146+
147+
<Form.Item
148+
name="isMaster"
149+
label="Master Environment"
150+
valuePropName="checked"
151+
>
152+
<Switch />
153+
</Form.Item>
154+
</Form>
155+
</Modal>
156+
);
157+
};
158+
159+
export default EditEnvironmentModal;

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import React from 'react';
2-
import { Table, Tag } from 'antd';
2+
import { Table, Tag, Button, Tooltip } from 'antd';
3+
import { EditOutlined } from '@ant-design/icons';
34
import { Environment } from '../types/environment.types';
45

6+
7+
58
interface EnvironmentsTableProps {
69
environments: Environment[];
710
loading: boolean;
811
onRowClick: (record: Environment) => void;
12+
onEditClick: (record: Environment) => void;
13+
914
}
1015

1116
/**
@@ -14,13 +19,17 @@ interface EnvironmentsTableProps {
1419
const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({
1520
environments,
1621
loading,
17-
onRowClick
22+
onRowClick,
23+
onEditClick,
1824
}) => {
1925
// Get color for environment type/stage
2026
const getTypeColor = (type: string): string => {
27+
if (!type) return 'default';
28+
2129
switch (type.toUpperCase()) {
2230
case 'DEV': return 'blue';
2331
case 'TEST': return 'orange';
32+
case 'PREPROD': return 'purple';
2433
case 'PROD': return 'green';
2534
default: return 'default';
2635
}
@@ -50,8 +59,8 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({
5059
dataIndex: 'environmentType',
5160
key: 'environmentType',
5261
render: (type: string) => (
53-
<Tag color={getTypeColor(type)}>
54-
{type.toUpperCase()}
62+
<Tag color={getTypeColor(type || '')}>
63+
{type ? type.toUpperCase() : 'UNKNOWN'}
5564
</Tag>
5665
),
5766
},
@@ -65,6 +74,24 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({
6574
</Tag>
6675
),
6776
},
77+
{
78+
title: 'Actions',
79+
key: 'actions',
80+
width: 100,
81+
render: (_: any, record: Environment) => (
82+
<Tooltip title="Edit Environment">
83+
<Button
84+
icon={<EditOutlined />}
85+
type="text"
86+
onClick={(e) => {
87+
e.stopPropagation(); // Prevent row click
88+
onEditClick(record);
89+
}}
90+
aria-label="Edit Environment"
91+
/>
92+
</Tooltip>
93+
),
94+
}
6895
];
6996

7097
return (

client/packages/lowcoder/src/pages/setting/environments/context/EnvironmentContext.tsx

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// src/contexts/EnvironmentContext.tsx
21
import React, {
32
createContext,
43
useContext,
@@ -7,10 +6,11 @@ import React, {
76
useCallback,
87
ReactNode,
98
} from "react";
10-
import { useHistory } from "react-router-dom";
9+
import { message } from "antd";
1110
import {
1211
getEnvironmentById,
1312
getEnvironments,
13+
updateEnvironment,
1414
} from "../services/environments.service";
1515
import { Environment } from "../types/environment.types";
1616

@@ -29,6 +29,7 @@ interface EnvironmentContextState {
2929
// Functions
3030
refreshEnvironment: (envId?: string) => Promise<void>;
3131
refreshEnvironments: () => Promise<void>;
32+
updateEnvironmentData: (envId: string, data: Partial<Environment>) => Promise<Environment>;
3233
}
3334

3435
const EnvironmentContext = createContext<EnvironmentContextState | undefined>(undefined);
@@ -101,6 +102,35 @@ export const EnvironmentProvider: React.FC<ProviderProps> = ({
101102
}
102103
}, []);
103104

105+
// Function to update an environment
106+
// Function to update an environment
107+
const updateEnvironmentData = useCallback(async (
108+
environmentId: string,
109+
data: Partial<Environment>
110+
): Promise<Environment> => {
111+
try {
112+
const updatedEnv = await updateEnvironment(environmentId, data);
113+
114+
// Show success message
115+
message.success("Environment updated successfully");
116+
117+
// Refresh the environments list
118+
fetchEnvironments();
119+
120+
// If we're viewing a single environment and it's the one we updated,
121+
// refresh that environment data as well
122+
if (environment && environment.environmentId === environmentId) {
123+
fetchEnvironment(environmentId);
124+
}
125+
126+
return updatedEnv;
127+
} catch (err) {
128+
const errorMessage = err instanceof Error ? err.message : "Failed to update environment";
129+
message.error(errorMessage);
130+
throw err;
131+
}
132+
}, [environment, fetchEnvironment, fetchEnvironments]);
133+
104134
// Initial data loading - just fetch environments list
105135
useEffect(() => {
106136
fetchEnvironments();
@@ -115,6 +145,7 @@ export const EnvironmentProvider: React.FC<ProviderProps> = ({
115145
error,
116146
refreshEnvironment: fetchEnvironment,
117147
refreshEnvironments: fetchEnvironments,
148+
updateEnvironmentData,
118149
};
119150

120151
return (

0 commit comments

Comments
 (0)