Skip to content

Environments UI Screens #1606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 69 commits into from
Apr 19, 2025
Merged
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
349fdf1
Add Env Listing Page Structure
iamfaran Apr 10, 2025
cc015e6
Add routing structure for Environments
iamfaran Apr 10, 2025
27451ab
Add Environments Table component
iamfaran Apr 10, 2025
4be0dad
Add Env Detail Page
iamfaran Apr 10, 2025
2e88e9f
Create useEnvironmentDetail Hook and add in Detail Page
iamfaran Apr 10, 2025
eb401ee
add workspaces list
iamfaran Apr 10, 2025
3326214
fix Auth headers
iamfaran Apr 10, 2025
c66a048
Add user groups in Env Detail Page
iamfaran Apr 10, 2025
2d6ec6b
setup workspace detail page
iamfaran Apr 10, 2025
fe7e3c1
add click on workspace list
iamfaran Apr 10, 2025
d39b6a0
fix filtering of apps
iamfaran Apr 10, 2025
f5987e2
setup data sources structure
iamfaran Apr 10, 2025
8c11ef5
fix data source error
iamfaran Apr 10, 2025
d9f7dd5
Add Environment Context
iamfaran Apr 10, 2025
46911b0
Add Workspace and UserGroup hooks
iamfaran Apr 10, 2025
9f2c181
Add useWorkspace hook
iamfaran Apr 10, 2025
bf39d50
refactor workspace detail page
iamfaran Apr 10, 2025
204890a
remove unused files
iamfaran Apr 11, 2025
058db37
add enterprise managed workspaces hook
iamfaran Apr 11, 2025
1348756
fix managed workspaces endpoint
iamfaran Apr 11, 2025
c96b993
add utility function for merge workspaces
iamfaran Apr 11, 2025
19c99c7
add managed/unmanged workspaces
iamfaran Apr 11, 2025
82ce3c3
add app enterprise methods
iamfaran Apr 11, 2025
06b3822
add managed/unmaged for apps
iamfaran Apr 11, 2025
a758d7e
Add environments list in Context
iamfaran Apr 14, 2025
ce9b5ba
Move Workspace/User-Group tabs to the seperate component
iamfaran Apr 14, 2025
a9fbce8
remove button from user-groups
iamfaran Apr 14, 2025
aa27421
remove unnecessary code from the Environment Detail page
iamfaran Apr 14, 2025
2690ddf
add useWorkspaces hook that returns merged workspaces
iamfaran Apr 14, 2025
aafb5f5
remove unnecessary imports
iamfaran Apr 14, 2025
0d87a21
Make a seperate AppsTab components and unified managed/unmanged apps
iamfaran Apr 14, 2025
4280e67
add deploy modal
iamfaran Apr 14, 2025
d8ed715
add datasource functions
iamfaran Apr 14, 2025
a520554
fix data sources tab
iamfaran Apr 14, 2025
10b7140
test generic approach
iamfaran Apr 15, 2025
23b8462
add user groups tab generic
iamfaran Apr 15, 2025
ed1f8da
add generic tab for apps
iamfaran Apr 15, 2025
2934db2
setup data sources generic
iamfaran Apr 15, 2025
b704492
fix data source payload
iamfaran Apr 15, 2025
f2dd6a5
add query services
iamfaran Apr 15, 2025
b4b8c1c
add query service tab
iamfaran Apr 15, 2025
83973af
add DeployModal in context
iamfaran Apr 15, 2025
8527dd9
Add deployment config for Datasource
iamfaran Apr 15, 2025
17bb62a
Add deployment config for Query Library
iamfaran Apr 15, 2025
5f393b0
wrap the provider
iamfaran Apr 16, 2025
d5035d6
Test update environment
iamfaran Apr 16, 2025
c1ab2b4
add edit functionality environment
iamfaran Apr 16, 2025
221be50
remove edit from environments table
iamfaran Apr 16, 2025
1b37846
Add managed tag in the header of workspace detail page
iamfaran Apr 16, 2025
6713592
fix environments table width
iamfaran Apr 16, 2025
4251c75
fix tables UI
iamfaran Apr 16, 2025
aac3868
fix data sources tab
iamfaran Apr 16, 2025
04c1a76
add audit link in environments table
iamfaran Apr 16, 2025
3ad52c0
add audit logs
iamfaran Apr 16, 2025
29c2ae2
Fixed workspace detail page header
iamfaran Apr 16, 2025
de01cd8
move all columns to config
iamfaran Apr 16, 2025
860f5bf
remove legacy columns from Deployitemslist
iamfaran Apr 16, 2025
cae995a
move all columns to config
iamfaran Apr 16, 2025
7a6626c
disable button unless managed
iamfaran Apr 17, 2025
72cfeab
add managed/unmanged tags in workspace table
iamfaran Apr 17, 2025
b40147f
fix breadcrumbs
iamfaran Apr 17, 2025
de46a00
fix back links
iamfaran Apr 17, 2025
0c802d0
show tooltip on the workspace detail page
iamfaran Apr 17, 2025
feb158c
fix error flicker
iamfaran Apr 17, 2025
0f89b5a
fix responsiveness detail page
iamfaran Apr 17, 2025
e15f9b6
fix tabs UI
iamfaran Apr 17, 2025
6c04714
replace edit dropdown with button
iamfaran Apr 17, 2025
a3dac7e
remove unused files/code
iamfaran Apr 18, 2025
fa725fa
Merge branch 'ee-setup' into environments-only
FalkWolsky Apr 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions client/packages/lowcoder/src/constants/routesURL.ts
Original file line number Diff line number Diff line change
@@ -24,6 +24,10 @@ export const AUDIT_LOG_DETAIL = "/setting/audit/:eventId/detail";
export const APP_USAGE_DASHBOARD = "/setting/app-usage";
export const APP_USAGE_DETAIL = "/setting/app-usage/:eventId/detail";

export const ENVIRONMENT_SETTING = "/setting/environments";
export const ENVIRONMENT_DETAIL = `${ENVIRONMENT_SETTING}/:environmentId`;
export const ENVIRONMENT_WORKSPACE_DETAIL = `${ENVIRONMENT_DETAIL}/workspaces/:workspaceId`;

export const OAUTH_PROVIDER_SETTING = "/setting/oauth-provider";
export const OAUTH_PROVIDER_DETAIL = "/setting/oauth-provider/detail";

@@ -120,3 +124,7 @@ export const buildSubscriptionSettingsLink = (subscriptionId: string, productId
export const buildSubscriptionInfoLink = (productId: string) => `${SUBSCRIPTION_SETTING}/info/${productId}`;

export const buildSupportTicketLink = (ticketId: string) => `${SUPPORT_URL}/details/${ticketId}`;

export const buildEnvironmentId = (environmentId: string) => `${ENVIRONMENT_SETTING}/${environmentId}`;
export const buildEnvironmentWorkspaceId = (environmentId: string, workspaceId: string) =>
`${ENVIRONMENT_SETTING}/${environmentId}/workspaces/${workspaceId}`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
import React, {useState} from "react";
import { useParams } from "react-router-dom";
import {
Spin,
Typography,
Card,
Tag,
Tabs,
Alert,
Descriptions,
Dropdown,
Menu,
Button,
Breadcrumb,
} from "antd";
import {
ReloadOutlined,
LinkOutlined,
ClusterOutlined,
TeamOutlined,
UserOutlined,
SyncOutlined,
EditOutlined,
EllipsisOutlined,
MoreOutlined,
HomeOutlined
} from "@ant-design/icons";

import { useEnvironmentContext } from "./context/EnvironmentContext";
import { workspaceConfig } from "./config/workspace.config";
import { userGroupsConfig } from "./config/usergroups.config";
import DeployableItemsTab from "./components/DeployableItemsTab";
import EditEnvironmentModal from "./components/EditEnvironmentModal";
import { Environment } from "./types/environment.types";
import history from "@lowcoder-ee/util/history";

const { Title, Text } = Typography;
const { TabPane } = Tabs;


/**
* Environment Detail Page Component
* Shows detailed information about a specific environment
*/
const EnvironmentDetail: React.FC = () => {
// Get environment ID from URL params
const {
environment,
isLoadingEnvironment,
error,
updateEnvironmentData
} = useEnvironmentContext();



const [isEditModalVisible, setIsEditModalVisible] = useState(false);
const [isUpdating, setIsUpdating] = useState(false);

// Handle edit menu item click
const handleEditClick = () => {
setIsEditModalVisible(true);
};

// Handle modal close
const handleCloseModal = () => {
setIsEditModalVisible(false);
};

// Handle save environment
const handleSaveEnvironment = async (environmentId: string, data: Partial<Environment>) => {
setIsUpdating(true);
try {
await updateEnvironmentData(environmentId, data);
handleCloseModal();
} catch (error) {
console.error('Failed to update environment:', error);
} finally {
setIsUpdating(false);
}
};

// Dropdown menu for environment actions
const actionsMenu = (
<Menu>
<Menu.Item key="edit" icon={<EditOutlined />} onClick={handleEditClick}>
Edit Environment
</Menu.Item>
{/* Add more menu items here if needed */}
</Menu>
);
debugger

if (isLoadingEnvironment) {
return (
<div style={{ display: 'flex', justifyContent: 'center', padding: '50px' }}>
<Spin size="large" tip="Loading environment..." />
</div>
);
}

if (error || !environment) {
return (
<Alert
message="Error loading environment"
description={error || "Environment not found"}
type="error"
showIcon
/>
);
}
return (
<div
className="environment-detail-container"
style={{ padding: "24px", flex: 1 }}
>
<Breadcrumb style={{ marginBottom: "16px" }}>
<Breadcrumb.Item>
<span
style={{ cursor: "pointer" }}
onClick={() => history.push("/setting/environments")}
>
<HomeOutlined /> Environments
</span>
</Breadcrumb.Item>
<Breadcrumb.Item>{environment.environmentName}</Breadcrumb.Item>
</Breadcrumb>

{/* Header with environment name and controls */}
{/* Header with environment name and controls */}
<div
className="environment-header"
style={{
marginBottom: "24px",
display: "flex",
justifyContent: "space-between",
alignItems: "flex-start",
flexWrap: "wrap",
gap: "16px",
}}
>
<div style={{ flex: "1 1 auto", minWidth: "200px" }}>
<Title level={3} style={{ margin: 0, wordBreak: "break-word" }}>
{environment.environmentName || "Unnamed Environment"}
</Title>
<Text type="secondary">ID: {environment.environmentId}</Text>
</div>
<div style={{ flexShrink: 0 }}>
<Button
icon={<EditOutlined />}
onClick={handleEditClick}
type="primary"
>
Edit Environment
</Button>
</div>
</div>

{/* Basic Environment Information Card - improved responsiveness */}
<Card
title="Environment Overview"
style={{ marginBottom: "24px" }}
extra={environment.isMaster && <Tag color="green">Master</Tag>}
>
<Descriptions
bordered
layout="vertical" // Change to vertical layout on smaller screens
column={{ xxl: 4, xl: 3, lg: 3, md: 2, sm: 1, xs: 1 }}
size="small" // Use smaller size on mobile
>
<Descriptions.Item label="Domain">
{environment.environmentFrontendUrl ? (
<a
href={environment.environmentFrontendUrl}
target="_blank"
rel="noopener noreferrer"
>
{environment.environmentFrontendUrl} <LinkOutlined />
</a>
) : (
"No domain set"
)}
</Descriptions.Item>
<Descriptions.Item label="Environment Type">
<Tag
color={
environment.environmentType === "production"
? "red"
: environment.environmentType === "testing"
? "orange"
: "blue"
}
>
{environment.environmentType}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="API Key Status">
{environment.environmentApikey ? (
<Tag color="green">Configured</Tag>
) : (
<Tag color="red">Not Configured</Tag>
)}
</Descriptions.Item>
<Descriptions.Item label="Master Environment">
{environment.isMaster ? "Yes" : "No"}
</Descriptions.Item>
</Descriptions>
</Card>

{/* Tabs for Workspaces and User Groups */}
<Tabs defaultActiveKey="workspaces">
<TabPane tab="Workspaces" key="workspaces">
{/* Using our new generic component with the workspace config */}
<DeployableItemsTab
environment={environment}
config={workspaceConfig}
title="Workspaces in this Environment"
/>
</TabPane>
<TabPane
tab={
<span>
<TeamOutlined /> User Groups
</span>
}
key="userGroups"
>
{/* Using our new generic component with the user group config */}
<DeployableItemsTab
environment={environment}
config={userGroupsConfig}
title="User Groups in this Environment"
/>
</TabPane>
</Tabs>
{/* Edit Environment Modal */}
{environment && (
<EditEnvironmentModal
visible={isEditModalVisible}
environment={environment}
onClose={handleCloseModal}
onSave={handleSaveEnvironment}
loading={isUpdating}
/>
)}
</div>
);
};

export default EnvironmentDetail;
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
export function Environments() {
return <></>;
}
import React from "react";
import { Switch, Route } from "react-router-dom";
import { EnvironmentProvider } from "./context/EnvironmentContext";
import EnvironmentsList from "./EnvironmentsList";
import EnvironmentScopedRoutes from "./components/EnvironmentScopedRoutes";

import {
ENVIRONMENT_SETTING,
ENVIRONMENT_DETAIL
} from "@lowcoder-ee/constants/routesURL";

/**
* Top-level Environments component that wraps all environment-related routes
* with the EnvironmentProvider for shared state management
*/
const Environments: React.FC = () => {
return (
<EnvironmentProvider>
<Switch>
{/* Route that shows the list of environments */}
<Route exact path={ENVIRONMENT_SETTING}>
<EnvironmentsList />
</Route>

{/* All other routes under /environments/:envId */}
<Route path={ENVIRONMENT_DETAIL}>
<EnvironmentScopedRoutes />
</Route>
</Switch>
</EnvironmentProvider>
);
};

export default Environments;
Loading
Loading