Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdffc683

Browse files
committed
Seperate Queries Tab
1 parent0a1879b commitdffc683

File tree

2 files changed

+276
-5
lines changed

2 files changed

+276
-5
lines changed

‎client/packages/lowcoder/src/pages/setting/environments/WorkspaceDetail.tsx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import { queryConfig } from "./config/query.config";
3636

3737
importAppsTabfrom"./components/AppsTab";
3838
importDataSourcesTabfrom"./components/DataSourcesTab";
39+
importQueriesTabfrom"./components/QueriesTab";
40+
3941
const{ Title, Text}=Typography;
4042
const{ TabPane}=Tabs;
4143

@@ -176,15 +178,13 @@ const WorkspaceDetail: React.FC = () => {
176178
workspace={workspace}
177179
/>
178180
</TabPane>
179-
180181
<TabPanetab={<span><CodeOutlined/> Queries</span>}key="queries">
181-
<DeployableItemsTab
182+
<QueriesTab
182183
environment={environment}
183-
config={queryConfig}
184-
additionalParams={{workspaceId:workspace.id}}
185-
title="Queries in this Workspace"
184+
workspace={workspace}
186185
/>
187186
</TabPane>
187+
188188
</Tabs>
189189
</div>
190190
);
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
importReact,{useState,useEffect}from'react';
2+
import{Card,Button,Divider,Alert,message,Table,Tag,Input,Space,Tooltip}from'antd';
3+
import{SyncOutlined,CloudUploadOutlined,CodeOutlined}from'@ant-design/icons';
4+
importTitlefrom'antd/lib/typography/Title';
5+
import{Environment}from'../types/environment.types';
6+
import{Workspace}from'../types/workspace.types';
7+
import{Query}from'../types/query.types';
8+
import{getMergedWorkspaceQueries}from'../services/query.service';
9+
import{Switch,Spin,Empty}from'antd';
10+
import{ManagedObjectType,setManagedObject,unsetManagedObject}from'../services/managed-objects.service';
11+
import{useDeployModal}from'../context/DeployModalContext';
12+
import{queryConfig}from'../config/query.config';
13+
14+
const{ Search}=Input;
15+
16+
interfaceQueriesTabProps{
17+
environment:Environment;
18+
workspace:Workspace;
19+
}
20+
21+
constQueriesTab:React.FC<QueriesTabProps>=({ environment, workspace})=>{
22+
const[queries,setQueries]=useState<Query[]>([]);
23+
const[stats,setStats]=useState({
24+
total:0,
25+
managed:0,
26+
unmanaged:0
27+
});
28+
const[loading,setLoading]=useState(false);
29+
const[refreshing,setRefreshing]=useState(false);
30+
const[error,setError]=useState<string|null>(null);
31+
const[searchText,setSearchText]=useState('');
32+
const{ openDeployModal}=useDeployModal();
33+
34+
// Fetch queries
35+
constfetchQueries=async()=>{
36+
if(!workspace.id||!environment)return;
37+
38+
setLoading(true);
39+
setError(null);
40+
41+
try{
42+
constresult=awaitgetMergedWorkspaceQueries(
43+
workspace.id,
44+
environment.environmentId,
45+
environment.environmentApikey,
46+
environment.environmentApiServiceUrl!
47+
);
48+
49+
setQueries(result.queries);
50+
setStats(result.stats);
51+
}catch(err){
52+
setError(errinstanceofError ?err.message :"Failed to fetch queries");
53+
}finally{
54+
setLoading(false);
55+
setRefreshing(false);
56+
}
57+
};
58+
59+
useEffect(()=>{
60+
fetchQueries();
61+
},[environment,workspace]);
62+
63+
// Handle refresh
64+
consthandleRefresh=()=>{
65+
setRefreshing(true);
66+
fetchQueries();
67+
};
68+
69+
// Toggle managed status
70+
consthandleToggleManaged=async(query:Query,checked:boolean)=>{
71+
setRefreshing(true);
72+
try{
73+
if(checked){
74+
awaitsetManagedObject(
75+
query.gid,
76+
environment.environmentId,
77+
ManagedObjectType.QUERY,
78+
query.name
79+
);
80+
}else{
81+
awaitunsetManagedObject(
82+
query.gid,
83+
environment.environmentId,
84+
ManagedObjectType.QUERY
85+
);
86+
}
87+
88+
// Update the query in state
89+
constupdatedQueries=queries.map(item=>{
90+
if(item.id===query.id){
91+
return{ ...item,managed:checked};
92+
}
93+
returnitem;
94+
});
95+
96+
setQueries(updatedQueries);
97+
98+
// Update stats
99+
constmanaged=updatedQueries.filter(q=>q.managed).length;
100+
setStats(prev=>({
101+
...prev,
102+
managed,
103+
unmanaged:prev.total-managed
104+
}));
105+
106+
message.success(`${query.name} is now${checked ?'Managed' :'Unmanaged'}`);
107+
returntrue;
108+
}catch(error){
109+
message.error(`Failed to change managed status for${query.name}`);
110+
returnfalse;
111+
}finally{
112+
setRefreshing(false);
113+
}
114+
};
115+
116+
// Filter queries based on search
117+
constfilteredQueries=searchText
118+
?queries.filter(query=>
119+
query.name.toLowerCase().includes(searchText.toLowerCase())||
120+
query.id.toLowerCase().includes(searchText.toLowerCase()))
121+
:queries;
122+
123+
// Table columns
124+
constcolumns=[
125+
{
126+
title:'Name',
127+
dataIndex:'name',
128+
key:'name',
129+
render:(text:string)=><spanclassName="query-name">{text}</span>
130+
},
131+
{
132+
title:'ID',
133+
dataIndex:'id',
134+
key:'id',
135+
ellipsis:true,
136+
},
137+
{
138+
title:'Creator',
139+
dataIndex:'creatorName',
140+
key:'creatorName',
141+
},
142+
{
143+
title:'Managed',
144+
key:'managed',
145+
render:(_:any,query:Query)=>(
146+
<Switch
147+
checked={!!query.managed}
148+
onChange={(checked:boolean)=>handleToggleManaged(query,checked)}
149+
loading={refreshing}
150+
size="small"
151+
/>
152+
),
153+
},
154+
{
155+
title:'Actions',
156+
key:'actions',
157+
render:(_:any,query:Query)=>(
158+
<SpaceonClick={(e)=>e.stopPropagation()}>
159+
<Tooltiptitle={!query.managed ?"Query must be managed before it can be deployed" :"Deploy this query to another environment"}>
160+
<Button
161+
type="primary"
162+
size="small"
163+
icon={<CloudUploadOutlined/>}
164+
onClick={()=>openDeployModal(query,queryConfig,environment)}
165+
disabled={!query.managed}
166+
>
167+
Deploy
168+
</Button>
169+
</Tooltip>
170+
</Space>
171+
),
172+
}
173+
];
174+
175+
return(
176+
<Card>
177+
{/* Header with refresh button */}
178+
<divstyle={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"16px"}}>
179+
<Titlelevel={5}>Queries in this Workspace</Title>
180+
<Button
181+
icon={<SyncOutlinedspin={refreshing}/>}
182+
onClick={handleRefresh}
183+
loading={loading}
184+
>
185+
Refresh
186+
</Button>
187+
</div>
188+
189+
{/* Stats display */}
190+
<divstyle={{display:'flex',flexWrap:'wrap',gap:'24px',marginBottom:'16px'}}>
191+
<div>
192+
<divstyle={{fontSize:'14px',color:'#8c8c8c'}}>Total Queries</div>
193+
<divstyle={{fontSize:'24px',fontWeight:600}}>{stats.total}</div>
194+
</div>
195+
<div>
196+
<divstyle={{fontSize:'14px',color:'#8c8c8c'}}>Managed</div>
197+
<divstyle={{fontSize:'24px',fontWeight:600}}>{stats.managed}</div>
198+
</div>
199+
<div>
200+
<divstyle={{fontSize:'14px',color:'#8c8c8c'}}>Unmanaged</div>
201+
<divstyle={{fontSize:'24px',fontWeight:600}}>{stats.unmanaged}</div>
202+
</div>
203+
</div>
204+
205+
<Dividerstyle={{margin:"16px 0"}}/>
206+
207+
{/* Error display */}
208+
{error&&(
209+
<Alert
210+
message="Error loading queries"
211+
description={error}
212+
type="error"
213+
showIcon
214+
style={{marginBottom:"16px"}}
215+
/>
216+
)}
217+
218+
{/* Configuration warnings */}
219+
{(!environment.environmentApikey||!environment.environmentApiServiceUrl)&&!error&&(
220+
<Alert
221+
message="Configuration Issue"
222+
description="Missing required configuration: API key or API service URL"
223+
type="warning"
224+
showIcon
225+
style={{marginBottom:"16px"}}
226+
/>
227+
)}
228+
229+
{/* Content */}
230+
{loading ?(
231+
<divstyle={{display:'flex',justifyContent:'center',padding:'20px'}}>
232+
<Spintip="Loading queries..."/>
233+
</div>
234+
) :queries.length===0 ?(
235+
<Empty
236+
description={error||"No queries found in this workspace"}
237+
image={Empty.PRESENTED_IMAGE_SIMPLE}
238+
/>
239+
) :(
240+
<>
241+
{/* Search Bar */}
242+
<divstyle={{marginBottom:16}}>
243+
<Search
244+
placeholder="Search queries by name or ID"
245+
allowClear
246+
onSearch={value=>setSearchText(value)}
247+
onChange={e=>setSearchText(e.target.value)}
248+
style={{width:300}}
249+
/>
250+
{searchText&&filteredQueries.length!==queries.length&&(
251+
<divstyle={{marginTop:8}}>
252+
Showing{filteredQueries.length} of{queries.length} queries
253+
</div>
254+
)}
255+
</div>
256+
257+
<Table
258+
columns={columns}
259+
dataSource={filteredQueries}
260+
rowKey="id"
261+
pagination={{pageSize:10}}
262+
size="middle"
263+
scroll={{x:'max-content'}}
264+
/>
265+
</>
266+
)}
267+
</Card>
268+
);
269+
};
270+
271+
exportdefaultQueriesTab;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp