diff --git a/client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx b/client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx
index b772bf373..a3a15ec03 100644
--- a/client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx
+++ b/client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx
@@ -93,12 +93,37 @@ const EnvironmentDetail: React.FC = () => {
if (error || !environment) {
return (
-
+
+
+
+ history.push("/setting/environments")}
+ >
+ Environments
+
+
+ Not Found
+
+
+
+
+
+ Environment Not Found
+
+
+ {error || "The environment you're looking for doesn't exist or you don't have permission to view it."}
+
+
+
+
+
);
}
diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx
index a58ac7d78..b7ae9bb06 100644
--- a/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx
+++ b/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx
@@ -1,9 +1,11 @@
// components/DeployItemModal.tsx
import React, { useState, useEffect } from 'react';
-import { Modal, Form, Select, Checkbox, Button, message, Spin, Input } from 'antd';
+import { Modal, Form, Select, Checkbox, Button, message, Spin, Input, Tag, Space } from 'antd';
import { Environment } from '../types/environment.types';
import { DeployableItem, BaseStats, DeployableItemConfig } from '../types/deployable-item.types';
import { useEnvironmentContext } from '../context/EnvironmentContext';
+import { getEnvironmentTagColor, formatEnvironmentType } from '../utils/environmentUtils';
+
interface DeployItemModalProps {
visible: boolean;
item: T | null;
@@ -84,6 +86,18 @@ function DeployItemModal({
form={form}
layout="vertical"
>
+ {/* Source environment display */}
+
+
+ {sourceEnvironment.environmentName}
+ {sourceEnvironment.environmentType && (
+
+ {formatEnvironmentType(sourceEnvironment.environmentType)}
+
+ )}
+
+
+
({
diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/DeployableItemsList.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/DeployableItemsList.tsx
index 63f8dda72..bed49855d 100644
--- a/client/packages/lowcoder/src/pages/setting/environments/components/DeployableItemsList.tsx
+++ b/client/packages/lowcoder/src/pages/setting/environments/components/DeployableItemsList.tsx
@@ -1,12 +1,14 @@
// components/DeployableItemsList.tsx
-import React from 'react';
-import { Table, Tag, Empty, Spin, Switch, Space, Button, Tooltip } from 'antd';
-import { CloudUploadOutlined } from '@ant-design/icons';
+import React, { useState } from 'react';
+import { Table, Tag, Empty, Spin, Switch, Space, Button, Tooltip, Input } from 'antd';
+import { CloudUploadOutlined, SearchOutlined } from '@ant-design/icons';
import history from '@lowcoder-ee/util/history';
import { DeployableItem, BaseStats, DeployableItemConfig } from '../types/deployable-item.types';
import { Environment } from '../types/environment.types';
import { useDeployModal } from '../context/DeployModalContext';
+const { Search } = Input;
+
interface DeployableItemsListProps {
items: T[];
loading: boolean;
@@ -30,6 +32,14 @@ function DeployableItemsList({
}: DeployableItemsListProps) {
const { openDeployModal } = useDeployModal();
+ const [searchText, setSearchText] = useState('');
+
+ // Filter items based on search
+ const filteredItems = searchText
+ ? items.filter(item =>
+ item.name.toLowerCase().includes(searchText.toLowerCase()) ||
+ item.id.toLowerCase().includes(searchText.toLowerCase()))
+ : items;
// Handle row click for navigation
const handleRowClick = (item: T) => {
@@ -53,8 +63,7 @@ function DeployableItemsList({
onToggleManaged,
openDeployModal,
additionalParams
- })
-
+ });
if (loading) {
return (
@@ -76,18 +85,36 @@ function DeployableItemsList({
const hasNavigation = config.buildDetailRoute({}) !== '#';
return (
- ({
- onClick: hasNavigation ? () => handleRowClick(record) : undefined,
- style: hasNavigation ? { cursor: 'pointer' } : undefined,
- })}
- />
+ <>
+ {/* Search Bar */}
+
+
setSearchText(value)}
+ onChange={e => setSearchText(e.target.value)}
+ style={{ width: 300 }}
+ />
+ {searchText && filteredItems.length !== items.length && (
+
+ Showing {filteredItems.length} of {items.length} {config.pluralLabel.toLowerCase()}
+
+ )}
+
+
+ ({
+ onClick: hasNavigation ? () => handleRowClick(record) : undefined,
+ style: hasNavigation ? { cursor: 'pointer' } : undefined,
+ })}
+ />
+ >
);
}
diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx
index 0208932d7..4f9150a9b 100644
--- a/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx
+++ b/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx
@@ -2,6 +2,7 @@ import React from 'react';
import { Table, Tag, Button, Tooltip, Space } from 'antd';
import { EditOutlined, AuditOutlined} from '@ant-design/icons';
import { Environment } from '../types/environment.types';
+import { getEnvironmentTagColor, formatEnvironmentType } from '../utils/environmentUtils';
@@ -20,19 +21,6 @@ const EnvironmentsTable: React.FC = ({
loading,
onRowClick,
}) => {
- // Get color for environment type/stage
- const getTypeColor = (type: string): string => {
- if (!type) return 'default';
-
- switch (type.toUpperCase()) {
- case 'DEV': return 'blue';
- case 'TEST': return 'orange';
- case 'PREPROD': return 'purple';
- case 'PROD': return 'green';
- default: return 'default';
- }
- };
-
// Open audit page in new tab
const openAuditPage = (environmentId: string, e: React.MouseEvent) => {
e.stopPropagation(); // Prevent row click from triggering
@@ -65,8 +53,8 @@ const EnvironmentsTable: React.FC = ({
dataIndex: 'environmentType',
key: 'environmentType',
render: (type: string) => (
-
- {type ? type.toUpperCase() : 'UNKNOWN'}
+
+ {formatEnvironmentType(type)}
),
},
diff --git a/client/packages/lowcoder/src/pages/setting/environments/utils/columnFactories.tsx b/client/packages/lowcoder/src/pages/setting/environments/utils/columnFactories.tsx
index b33685ab7..45c69c580 100644
--- a/client/packages/lowcoder/src/pages/setting/environments/utils/columnFactories.tsx
+++ b/client/packages/lowcoder/src/pages/setting/environments/utils/columnFactories.tsx
@@ -69,6 +69,13 @@ export function createManagedColumn(
return {
title: 'Managed',
key: 'managed',
+ filterMode: 'menu',
+ filters: [
+ { text: 'Managed', value: true },
+ { text: 'Unmanaged', value: false },
+ ],
+ onFilter: (value, record) => record.managed === value,
+ filterMultiple: false,
render: (_, record: T) => (
@@ -178,6 +185,13 @@ export function createPublishedColumn(): Colu
title: 'Status',
dataIndex: 'published',
key: 'published',
+ filterMode: 'menu',
+ filters: [
+ { text: 'Published', value: true },
+ { text: 'Unpublished', value: false },
+ ],
+ onFilter: (value, record) => record.published === value,
+ filterMultiple: false,
render: (published: boolean) => (
{published ? 'Published' : 'Unpublished'}
diff --git a/client/packages/lowcoder/src/pages/setting/environments/utils/environmentUtils.ts b/client/packages/lowcoder/src/pages/setting/environments/utils/environmentUtils.ts
new file mode 100644
index 000000000..f3f5d5c1b
--- /dev/null
+++ b/client/packages/lowcoder/src/pages/setting/environments/utils/environmentUtils.ts
@@ -0,0 +1,46 @@
+/**
+ * Utility functions for environment-related features
+ */
+
+/**
+ * Get the appropriate color for an environment tag based on its type
+ * @param envType The environment type/stage (e.g. 'PROD', 'DEV', 'STAGING')
+ * @returns A color string to use with Ant Design's Tag component
+ */
+export const getEnvironmentTagColor = (envType: string | undefined): string => {
+ if (!envType) return 'default';
+
+ // Normalize to uppercase for consistent comparison
+ const type = envType.toUpperCase();
+
+ switch (type) {
+ // Production environment
+ case 'PROD':
+ return 'red'; // Red for production - indicates caution
+
+ // Pre-production environment
+ case 'PREPROD':
+ return 'orange'; // Orange for pre-production
+
+ // Test environment
+ case 'TEST':
+ return 'purple'; // Purple for test environment
+
+ // Development environment
+ case 'DEV':
+ return 'green'; // Green for development - safe to use
+
+ default:
+ return 'default'; // Default gray for unknown types
+ }
+};
+
+/**
+ * Format an environment type for display
+ * @param envType The environment type string
+ * @returns Formatted environment type string
+ */
+export const formatEnvironmentType = (envType: string | undefined): string => {
+ if (!envType) return 'UNKNOWN';
+ return envType.toUpperCase();
+};
\ No newline at end of file