Skip to content

Commit 3a5a245

Browse files
authored
feat: ui based client (#85)
1 parent 5f2c398 commit 3a5a245

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2809
-1001
lines changed

Cargo.lock

Lines changed: 348 additions & 244 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ version = "0.0.1"
1515
[workspace.dependencies]
1616
async-trait = "0.1.83"
1717
bytes = { version = "1.1" }
18-
chrono = { version = "0.4.38", features = ["serde"] }
18+
chrono = { version = "0.4.38, <0.4.40", features = ["serde"] }
1919
clap = { version = "4.5", features = ["derive"] }
20-
delta_kernel = { version = "0.5.0", features = [
20+
delta_kernel = { version = "0.7", features = [
2121
"tokio",
2222
"developer-visibility",
2323
"default-engine",
24+
"arrow_54",
2425
] }
2526
futures = { version = "0.3.31" }
2627
http = { version = "1.2" }

app/src-tauri/src/client.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
use delta_sharing_common::models::catalogs::v1::{CatalogInfo, CreateCatalogRequest};
2+
use delta_sharing_common::models::credentials::v1::{
3+
CreateCredentialRequest, CredentialInfo, Purpose,
4+
};
5+
use delta_sharing_common::models::external_locations::v1::{
6+
CreateExternalLocationRequest, ExternalLocationInfo,
7+
};
8+
use delta_sharing_common::models::recipients::v1::{CreateRecipientRequest, RecipientInfo};
29
use delta_sharing_common::models::schemas::v1::{CreateSchemaRequest, SchemaInfo};
10+
use delta_sharing_common::models::shares::v1::{CreateShareRequest, ShareInfo};
311
use delta_sharing_common::rest::client::UnityCatalogClient;
412
use futures::TryStreamExt;
513
use tauri::State;
@@ -78,3 +86,136 @@ pub async fn delete_schema(
7886
) -> Result<()> {
7987
Ok(state.schemas().delete(catalog, name, force).await?)
8088
}
89+
90+
#[tauri::command]
91+
pub async fn list_credentials(
92+
state: State<'_, UnityCatalogClient>,
93+
purpose: Option<Purpose>,
94+
max_results: Option<i32>,
95+
) -> Result<Vec<CredentialInfo>> {
96+
Ok(state
97+
.credentials()
98+
.list(purpose, max_results)
99+
.try_collect()
100+
.await?)
101+
}
102+
103+
#[tauri::command]
104+
pub async fn get_credential(
105+
state: State<'_, UnityCatalogClient>,
106+
name: String,
107+
) -> Result<CredentialInfo> {
108+
Ok(state.credentials().get(name).await?)
109+
}
110+
111+
#[tauri::command]
112+
pub async fn create_credential(
113+
state: State<'_, UnityCatalogClient>,
114+
request: CreateCredentialRequest,
115+
) -> Result<CredentialInfo> {
116+
Ok(state.credentials().create_credential(&request).await?)
117+
}
118+
119+
#[tauri::command]
120+
pub async fn delete_credential(state: State<'_, UnityCatalogClient>, name: String) -> Result<()> {
121+
Ok(state.credentials().delete(name).await?)
122+
}
123+
124+
#[tauri::command]
125+
pub async fn list_external_locations(
126+
state: State<'_, UnityCatalogClient>,
127+
max_results: Option<i32>,
128+
) -> Result<Vec<ExternalLocationInfo>> {
129+
Ok(state
130+
.external_locations()
131+
.list(max_results)
132+
.try_collect()
133+
.await?)
134+
}
135+
136+
#[tauri::command]
137+
pub async fn get_external_location(
138+
state: State<'_, UnityCatalogClient>,
139+
name: String,
140+
) -> Result<ExternalLocationInfo> {
141+
Ok(state.external_locations().get(name).await?)
142+
}
143+
144+
#[tauri::command]
145+
pub async fn create_external_location(
146+
state: State<'_, UnityCatalogClient>,
147+
request: CreateExternalLocationRequest,
148+
) -> Result<ExternalLocationInfo> {
149+
Ok(state
150+
.external_locations()
151+
.create_external_location(&request)
152+
.await?)
153+
}
154+
155+
#[tauri::command]
156+
pub async fn delete_external_location(
157+
state: State<'_, UnityCatalogClient>,
158+
name: String,
159+
force: Option<bool>,
160+
) -> Result<()> {
161+
Ok(state.external_locations().delete(name, force).await?)
162+
}
163+
164+
#[tauri::command]
165+
pub async fn list_recipients(
166+
state: State<'_, UnityCatalogClient>,
167+
max_results: Option<i32>,
168+
) -> Result<Vec<RecipientInfo>> {
169+
Ok(state.recipients().list(max_results).try_collect().await?)
170+
}
171+
172+
#[tauri::command]
173+
pub async fn get_recipient(
174+
state: State<'_, UnityCatalogClient>,
175+
name: String,
176+
) -> Result<RecipientInfo> {
177+
Ok(state.recipients().get(name).await?)
178+
}
179+
180+
#[tauri::command]
181+
pub async fn create_recipient(
182+
state: State<'_, UnityCatalogClient>,
183+
request: CreateRecipientRequest,
184+
) -> Result<RecipientInfo> {
185+
Ok(state.recipients().create_recipient(&request).await?)
186+
}
187+
188+
#[tauri::command]
189+
pub async fn delete_recipient(state: State<'_, UnityCatalogClient>, name: String) -> Result<()> {
190+
Ok(state.recipients().delete(name).await?)
191+
}
192+
193+
#[tauri::command]
194+
pub async fn list_shares(
195+
state: State<'_, UnityCatalogClient>,
196+
max_results: Option<i32>,
197+
) -> Result<Vec<ShareInfo>> {
198+
Ok(state.shares().list(max_results).try_collect().await?)
199+
}
200+
201+
#[tauri::command]
202+
pub async fn get_share(
203+
state: State<'_, UnityCatalogClient>,
204+
name: String,
205+
include_shared_data: Option<bool>,
206+
) -> Result<ShareInfo> {
207+
Ok(state.shares().get(name, include_shared_data).await?)
208+
}
209+
210+
#[tauri::command]
211+
pub async fn create_share(
212+
state: State<'_, UnityCatalogClient>,
213+
request: CreateShareRequest,
214+
) -> Result<ShareInfo> {
215+
Ok(state.shares().create_share(&request).await?)
216+
}
217+
218+
#[tauri::command]
219+
pub async fn delete_share(state: State<'_, UnityCatalogClient>, name: String) -> Result<()> {
220+
Ok(state.shares().delete(name).await?)
221+
}

app/src-tauri/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ pub fn run() {
2323
client::get_schema,
2424
client::create_schema,
2525
client::delete_schema,
26+
client::list_credentials,
27+
client::get_credential,
28+
client::create_credential,
29+
client::delete_credential,
30+
client::list_external_locations,
31+
client::get_external_location,
32+
client::create_external_location,
33+
client::delete_external_location,
34+
client::list_recipients,
35+
client::get_recipient,
36+
client::create_recipient,
37+
client::delete_recipient,
38+
client::list_shares,
39+
client::get_share,
40+
client::create_share,
41+
client::delete_share,
2642
])
2743
.setup(|app| {
2844
app.manage(unity_client);

app/src/App.tsx

Lines changed: 26 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,57 @@
1-
import { useState, useRef, useCallback, useEffect } from "react";
21
import "./App.css";
32
import {
4-
DrawerBody,
5-
DrawerHeader,
6-
DrawerHeaderTitle,
7-
InlineDrawer,
83
makeStyles,
9-
mergeClasses,
104
tokens,
5+
Toolbar,
6+
ToolbarButton,
7+
shorthands,
118
} from "@fluentui/react-components";
12-
import TreeView from "./components/TreeView";
9+
import Explorer from "./components/Explorer";
10+
import { SettingsRegular } from "@fluentui/react-icons";
1311

1412
const useStyles = makeStyles({
1513
root: {
16-
// border: "2px solid #ccc",
17-
overflow: "hidden",
18-
1914
display: "flex",
2015
height: "100vh",
2116
width: "100vw",
22-
// backgroundColor: "#fff",
23-
userSelect: "auto",
24-
},
25-
26-
rootResizerActive: {
27-
userSelect: "none",
28-
},
29-
30-
container: {
31-
position: "relative",
17+
flexDirection: "column",
3218
},
3319

34-
drawer: {
35-
willChange: "width",
36-
transitionProperty: "width",
37-
transitionDuration: "16.666ms", // 60fps
20+
toolbar: {
21+
borderBottomColor: tokens.colorNeutralForeground4,
22+
borderBottomWidth: "1px",
23+
borderBottomStyle: "solid",
3824
},
3925

40-
resizer: {
41-
borderRight: `1px solid ${tokens.colorNeutralBackground5}`,
42-
43-
width: "8px",
44-
position: "absolute",
45-
top: 0,
46-
right: 0,
47-
bottom: 0,
48-
cursor: "col-resize",
49-
resize: "horizontal",
50-
26+
button: {
27+
...shorthands.borderColor(tokens.colorBrandStroke2),
5128
":hover": {
52-
borderRightWidth: "4px",
29+
...shorthands.borderColor(tokens.colorNeutralStroke1),
5330
},
5431
},
5532

56-
resizerActive: {
57-
borderRightWidth: "4px",
58-
borderRightColor: tokens.colorNeutralBackground5Pressed,
59-
},
60-
6133
content: {
62-
margin: `${tokens.spacingVerticalXL} ${tokens.spacingHorizontalXL}`,
63-
flex: "1",
34+
flex: 1,
6435
},
6536
});
6637

6738
function App() {
6839
const styles = useStyles();
6940

70-
const animationFrame = useRef<number>(0);
71-
const sidebarRef = useRef<HTMLDivElement>(null);
72-
const [isResizing, setIsResizing] = useState(false);
73-
const [sidebarWidth, setSidebarWidth] = useState(320);
74-
75-
const startResizing = useCallback(() => setIsResizing(true), []);
76-
const stopResizing = useCallback(() => setIsResizing(false), []);
77-
78-
const resize = useCallback(
79-
({ clientX }: { clientX: number }) => {
80-
animationFrame.current = requestAnimationFrame(() => {
81-
if (isResizing && sidebarRef.current) {
82-
setSidebarWidth(
83-
clientX -
84-
sidebarRef.current.getBoundingClientRect().left,
85-
);
86-
}
87-
});
88-
},
89-
[isResizing],
90-
);
91-
92-
const ResizeComponent: React.FC = () => (
93-
<div
94-
className={mergeClasses(
95-
styles.resizer,
96-
isResizing && styles.resizerActive,
97-
)}
98-
onMouseDown={startResizing}
99-
/>
100-
);
101-
102-
useEffect(() => {
103-
window.addEventListener("mousemove", resize);
104-
window.addEventListener("mouseup", stopResizing);
105-
106-
return () => {
107-
cancelAnimationFrame(animationFrame.current);
108-
window.removeEventListener("mousemove", resize);
109-
window.removeEventListener("mouseup", stopResizing);
110-
};
111-
}, [resize, stopResizing]);
112-
11341
return (
114-
<div
115-
className={mergeClasses(
116-
styles.root,
117-
isResizing && styles.rootResizerActive,
118-
)}
119-
>
120-
<div className={styles.container}>
121-
<InlineDrawer
122-
open
123-
ref={sidebarRef}
124-
className={styles.drawer}
125-
style={{ width: `${sidebarWidth}px` }}
126-
onMouseDown={(e) => e.preventDefault()}
127-
>
128-
<DrawerHeader>
129-
<DrawerHeaderTitle>Catalog Browser</DrawerHeaderTitle>
130-
</DrawerHeader>
131-
<DrawerBody>
132-
<TreeView />
133-
</DrawerBody>
134-
</InlineDrawer>
135-
<ResizeComponent />
42+
<div className={styles.root}>
43+
<div className={styles.toolbar}>
44+
<Toolbar size="medium">
45+
<ToolbarButton
46+
className={styles.button}
47+
appearance="subtle"
48+
icon={<SettingsRegular />}
49+
/>
50+
</Toolbar>
51+
</div>
52+
<div className={styles.content}>
53+
<Explorer />
13654
</div>
137-
<p className={styles.content}>
138-
Resize the drawer to see the change
139-
</p>
14055
</div>
14156
);
14257
}

0 commit comments

Comments
 (0)