Skip to content

Commit 19c99c7

Browse files
committed
add managed/unmanged workspaces
1 parent c96b993 commit 19c99c7

File tree

3 files changed

+98
-33
lines changed

3 files changed

+98
-33
lines changed

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

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from "react";
1+
import React, {useState} from "react";
22
import { useParams } from "react-router-dom";
33
import {
44
Spin,
@@ -13,6 +13,7 @@ import {
1313
Button,
1414
Statistic,
1515
Divider,
16+
message
1617
} from "antd";
1718
import {
1819
ReloadOutlined,
@@ -29,6 +30,8 @@ import { useEnvironmentWorkspaces } from "./hooks/useEnvironmentWorkspaces";
2930
import { useEnvironmentUserGroups } from "./hooks/useEnvironmentUserGroups";
3031
import { useManagedWorkspaces } from "./hooks/enterprise/useManagedWorkspaces";
3132
import { getMergedWorkspaces } from "./utils/getMergedWorkspaces";
33+
import { Workspace } from "./types/workspace.types";
34+
import { connectManagedWorkspace, unconnectManagedWorkspace } from "./services/enterprise.service";
3235

3336

3437
const { Title, Text } = Typography;
@@ -38,6 +41,12 @@ const { TabPane } = Tabs;
3841
* Environment Detail Page Component
3942
* Shows detailed information about a specific environment
4043
*/
44+
45+
type WorkspaceStats = {
46+
total: number;
47+
managed: number;
48+
unmanaged: number;
49+
};
4150
const EnvironmentDetail: React.FC = () => {
4251
// Get environment ID from URL params
4352
const {
@@ -72,6 +81,22 @@ const EnvironmentDetail: React.FC = () => {
7281

7382
// Use the custom hook to handle data fetching and state management
7483
// Use the custom hook to handle data fetching and state management
84+
85+
const [mergedWorkspaces, setMergedWorkspaces] = useState<Workspace[]>([]);
86+
const [workspaceStats, setWorkspaceStats] = useState<WorkspaceStats>({
87+
total: 0,
88+
managed: 0,
89+
unmanaged: 0,
90+
});
91+
92+
93+
React.useEffect(() => {
94+
if (workspaces && managedWorkspaces) {
95+
const { merged, stats } = getMergedWorkspaces(workspaces, managedWorkspaces);
96+
setMergedWorkspaces(merged);
97+
setWorkspaceStats(stats);
98+
}
99+
}, [workspaces, managedWorkspaces]);
75100

76101
// If loading, show spinner
77102
if (envLoading) {
@@ -121,7 +146,39 @@ const EnvironmentDetail: React.FC = () => {
121146
);
122147
}
123148

124-
const { merged, stats: workspaceStats } = getMergedWorkspaces(workspaces, managedWorkspaces);
149+
const { merged, stats: initialStats } = getMergedWorkspaces(workspaces, managedWorkspaces);
150+
151+
152+
153+
const handleToggleManaged = async (workspace: Workspace, checked: boolean) => {
154+
try {
155+
console.log("WORKSPACE", workspace);
156+
if (checked) {
157+
await connectManagedWorkspace(environment.environmentId, workspace.name, workspace.gid!);
158+
} else {
159+
await unconnectManagedWorkspace(workspace.gid!);
160+
}
161+
162+
// Optimistically update the local state
163+
const updatedList = mergedWorkspaces.map((w) =>
164+
w.id === workspace.id ? { ...w, managed: checked } : w
165+
);
166+
167+
const updatedManagedCount = updatedList.filter((w) => w.managed).length;
168+
169+
setMergedWorkspaces(updatedList);
170+
setWorkspaceStats({
171+
total: updatedList.length,
172+
managed: updatedManagedCount,
173+
unmanaged: updatedList.length - updatedManagedCount,
174+
});
175+
176+
message.success(`${workspace.name} is now ${checked ? 'Managed' : 'Unmanaged'}`);
177+
} catch (err) {
178+
message.error(`Failed to toggle managed state for ${workspace.name}`);
179+
}
180+
};
181+
125182

126183
return (
127184
<div className="environment-detail-container" style={{ padding: "24px" }}>
@@ -297,10 +354,11 @@ const EnvironmentDetail: React.FC = () => {
297354

298355
{/* Workspaces List */}
299356
<WorkspacesList
300-
workspaces={merged}
357+
workspaces={mergedWorkspaces} // ⬅️ Use local state!
301358
loading={workspacesLoading && !workspacesError}
302359
error={workspacesError}
303360
environmentId={environment.environmentId}
361+
onToggleManaged={handleToggleManaged} // ⬅️ Add this to enable toggles
304362
/>
305363
</Card>
306364
</TabPane>

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

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { Table, Tag, Empty, Spin } from 'antd';
2+
import { Table, Tag, Empty, Spin, Switch, Space } from 'antd';
33
import { Workspace } from '../types/workspace.types';
44
import history from '@lowcoder-ee/util/history';
55
import { buildEnvironmentWorkspaceId } from '@lowcoder-ee/constants/routesURL';
@@ -9,18 +9,18 @@ interface WorkspacesListProps {
99
loading: boolean;
1010
error?: string | null;
1111
environmentId: string;
12+
onToggleManaged?: (workspace: Workspace, checked: boolean) => void;
13+
refreshing?: boolean;
1214
}
1315

14-
/**
15-
* Component to display a list of workspaces in a table
16-
*/
1716
const WorkspacesList: React.FC<WorkspacesListProps> = ({
1817
workspaces,
1918
loading,
2019
error,
2120
environmentId,
21+
onToggleManaged,
22+
refreshing = false,
2223
}) => {
23-
// Format timestamp to date string
2424
const formatDate = (timestamp?: number): string => {
2525
if (!timestamp) return 'N/A';
2626
const date = new Date(timestamp);
@@ -31,7 +31,6 @@ const WorkspacesList: React.FC<WorkspacesListProps> = ({
3131
history.push(`${buildEnvironmentWorkspaceId(environmentId, workspace.id)}`);
3232
};
3333

34-
// Table columns definition
3534
const columns = [
3635
{
3736
title: 'Name',
@@ -48,9 +47,7 @@ const WorkspacesList: React.FC<WorkspacesListProps> = ({
4847
title: 'Role',
4948
dataIndex: 'role',
5049
key: 'role',
51-
render: (role: string) => (
52-
<span>{role}</span>
53-
),
50+
render: (role: string) => <span>{role}</span>,
5451
},
5552
{
5653
title: 'Creation Date',
@@ -71,14 +68,27 @@ const WorkspacesList: React.FC<WorkspacesListProps> = ({
7168
title: 'Managed',
7269
key: 'managed',
7370
render: (record: Workspace) => (
74-
<Tag color={record.managed ? 'green' : 'default'}>
75-
{record.managed ? 'Managed' : 'Unmanaged'}
76-
</Tag>
71+
<Space>
72+
<Tag color={record.managed ? 'green' : 'default'}>
73+
{record.managed ? 'Managed' : 'Unmanaged'}
74+
</Tag>
75+
{onToggleManaged && (
76+
<Switch
77+
size="small"
78+
checked={record.managed}
79+
loading={refreshing}
80+
onClick={(checked,e) => {
81+
e.stopPropagation(); // ✅ THIS STOPS the row from being triggered
82+
onToggleManaged(record, checked);
83+
}}
84+
onChange={() => {}}
85+
/>
86+
)}
87+
</Space>
7788
),
7889
},
7990
];
8091

81-
// If loading, show spinner
8292
if (loading) {
8393
return (
8494
<div style={{ display: 'flex', justifyContent: 'center', padding: '20px' }}>
@@ -87,7 +97,6 @@ const WorkspacesList: React.FC<WorkspacesListProps> = ({
8797
);
8898
}
8999

90-
// If no workspaces or error, show empty state
91100
if (!workspaces || workspaces.length === 0 || error) {
92101
return (
93102
<Empty
@@ -106,7 +115,7 @@ const WorkspacesList: React.FC<WorkspacesListProps> = ({
106115
size="middle"
107116
onRow={(record) => ({
108117
onClick: () => handleRowClick(record),
109-
style: { cursor: 'pointer' }, // Add pointer cursor to indicate clickable rows
118+
style: { cursor: 'pointer' },
110119
})}
111120
/>
112121
);

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

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ export async function getManagedWorkspaces(
4141

4242
export async function connectManagedWorkspace(
4343
environmentId: string,
44-
apiServiceUrl: string,
4544
orgName: string,
46-
orgTags: string[] = []
45+
org_gid: string, // ✅ not optional
46+
orgTags: string[] = [],
4747
) {
48-
if (!environmentId || !apiServiceUrl || !orgName) {
48+
if (!environmentId || !orgName || !org_gid) {
4949
throw new Error("Missing required params to connect org");
5050
}
5151

@@ -54,9 +54,10 @@ export async function connectManagedWorkspace(
5454
environment_id: environmentId,
5555
org_name: orgName,
5656
org_tags: orgTags,
57+
org_gid,
5758
};
5859

59-
const res = await axios.post(`${apiServiceUrl}/api/plugins/enterprise/org`, payload);
60+
const res = await axios.post(`/api/plugins/enterprise/org`, payload);
6061
return res.data;
6162
} catch (err) {
6263
const errorMsg = err instanceof Error ? err.message : "Failed to connect org";
@@ -67,27 +68,24 @@ export async function connectManagedWorkspace(
6768

6869

6970

70-
71-
72-
7371
/**
7472
* Fetch workspaces for a specific environment
7573
* @param apiServiceUrl - API service URL for the environment
7674
* @param orgId - ID of the workspace
7775
*
7876
*/
79-
export async function unconnectManagedWorkspace(
80-
apiServiceUrl: string,
81-
orgId: string
82-
) {
83-
if (!apiServiceUrl || !orgId) {
84-
throw new Error("Missing apiServiceUrl or orgId");
77+
export async function unconnectManagedWorkspace(orgGid: string) {
78+
if (!orgGid) {
79+
throw new Error("Missing orgGid to unconnect workspace");
8580
}
8681

8782
try {
88-
await axios.delete(`${apiServiceUrl}/api/plugins/enterprise/org/${orgId}`);
83+
await axios.delete(`/api/plugins/enterprise/org`, {
84+
params: { orgGid }, // ✅ pass as query param
85+
});
8986
} catch (err) {
90-
const errorMsg = err instanceof Error ? err.message : "Failed to unconnect org";
87+
const errorMsg =
88+
err instanceof Error ? err.message : "Failed to unconnect org";
9189
message.error(errorMsg);
9290
throw err;
9391
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy