Skip to content

Commit 9ad0c63

Browse files
ui tweaks
1 parent 5ddffda commit 9ad0c63

10 files changed

Lines changed: 172 additions & 63 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ node_modules
22
__pycache__
33
.DS_Store
44
.vscode
5-
.databricks
5+
.databricks
6+
.env

app.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
11
command: ["uvicorn", "backend.main:app"]
2+
3+
env:
4+
- name: DATABRICKS_HOSTNAME
5+
valueFrom: secrets
6+
7+
- name: DATABRICKS_HTTP_PATH
8+
valueFrom: secrets
9+
10+
- name: DATABRICKS_ACCESS_TOKEN
11+
valueFrom: secrets
12+
13+
- name: DATABRICKS_CATALOG
14+
valueFrom: secrets
15+
16+
- name: DATABRICKS_SCHEMA
17+
valueFrom: secrets

backend/main.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
from fastapi import FastAPI, HTTPException, Request
55
from fastapi.staticfiles import StaticFiles
66
from fastapi.responses import FileResponse
7+
from dotenv import load_dotenv
78

8-
host = ""
9-
http_path = ""
10-
access_token = ""
9+
load_dotenv()
10+
11+
host = os.getenv("DATABRICKS_HOSTNAME")
12+
http_path = os.getenv("DATABRICKS_HTTP_PATH")
13+
access_token = os.getenv("DATABRICKS_ACCESS_TOKEN")
14+
catalog = os.getenv("DATABRICKS_CATALOG")
15+
schema = os.getenv("DATABRICKS_SCHEMA")
1116

1217
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
1318
logger = logging.getLogger(__name__)
@@ -34,16 +39,19 @@ async def health_check():
3439
async def get_classification():
3540
connection = get_databricks_connection()
3641
cursor = connection.cursor()
37-
cursor.execute('SELECT resource_category, resource_type, total_count FROM cq_catalog.cloudquery.cloud_assets_counts')
42+
classification_query = f'SELECT resource_category, resource_type, resource_type_label, total_count FROM {catalog}.{schema}.cloud_assets_counts'
43+
logger.info(f'Executing classification query: {classification_query}')
44+
cursor.execute(classification_query)
3845
result = cursor.fetchall()
3946
cursor.close()
4047
connection.close()
4148

4249
data = {}
4350
for row in result:
44-
resource_category = row[0]
51+
resource_category = row[0] or "Unknown"
4552
resource_type = row[1]
46-
total_count = row[2]
53+
resource_type_label = row[2] if row[2] else row[1]
54+
total_count = row[3]
4755

4856
if resource_category not in data:
4957
data[resource_category] = {
@@ -55,7 +63,8 @@ async def get_classification():
5563
# Add the type to the category
5664
data[resource_category]["types"].append({
5765
"resource_type": resource_type,
58-
"total_count": total_count
66+
"resource_type_label": resource_type_label,
67+
"total_count": total_count,
5968
})
6069

6170
data[resource_category]["total_count"] += total_count
@@ -97,6 +106,12 @@ def compose_where_clause(filter_array):
97106
conditions.append(f"`{field}` != '{value}'")
98107
elif operator == "contains":
99108
conditions.append(f"`{field}` LIKE '%{value}%'")
109+
elif operator == "doesNotContain":
110+
conditions.append(f"`{field}` NOT LIKE '%{value}%'")
111+
elif operator == "startsWith":
112+
conditions.append(f"`{field}` LIKE '{value}%'")
113+
elif operator == "endsWith":
114+
conditions.append(f"`{field}` LIKE '%{value}'")
100115
# Add more operators as needed
101116

102117
if conditions:
@@ -140,12 +155,14 @@ def compose_order_by_clause(sort_array):
140155
order_by_clause = ""
141156

142157
# Get total count first with filter
143-
count_query = f'SELECT COUNT(*) as total FROM cq_catalog.cloudquery.cloud_assets {where_clause}'
158+
count_query = f'SELECT COUNT(*) as total FROM {catalog}.{schema}.cloud_assets {where_clause}'
159+
logger.info(f'Executing count query: {count_query}')
144160
cursor.execute(count_query)
145161
total_count = cursor.fetchone()[0]
146162

147163
# Get paginated data with filter and sorting
148-
data_query = f'SELECT * FROM cq_catalog.cloudquery.cloud_assets {where_clause} {order_by_clause} LIMIT {page_size} OFFSET {offset}'
164+
data_query = f'SELECT * FROM {catalog}.{schema}.cloud_assets {where_clause} {order_by_clause} LIMIT {page_size} OFFSET {offset}'
165+
logger.info(f'Executing data query: {data_query}')
149166
cursor.execute(data_query)
150167
result = cursor.fetchall()
151168

frontend/src/App.tsx

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import { useEffect } from "react";
22
import CssBaseline from "@mui/material/CssBaseline";
33
import { createTheme, ThemeProvider } from "@mui/material/styles";
44
import Box from "@mui/material/Box";
5-
import Stack from "@mui/material/Stack";
5+
import SearchIcon from "@mui/icons-material/Search";
66
import { createThemeOptions } from "@cloudquery/cloud-ui";
77
import { MuiChipsInput } from "mui-chips-input";
88
import { SidePanel } from "./components/SidePanel";
99
import { InventoryTable } from "./components/InventoryTable";
1010
import { useDatabricks } from "./hooks/useDatabricks";
1111
import { useChips } from "./hooks/useChips";
12+
import logo from "./assets/logo.svg";
1213

1314
const cloudUITheme = createThemeOptions();
1415
const theme = createTheme(cloudUITheme);
@@ -29,6 +30,8 @@ function App() {
2930
selectedCategory,
3031
selectedType,
3132
rowCount,
33+
columnVisibilityModel,
34+
setColumnVisibilityModel,
3235
} = useDatabricks();
3336

3437
const handleManualClauseChange = (newChips: string[]) => {
@@ -65,8 +68,27 @@ function App() {
6568
return (
6669
<ThemeProvider theme={theme}>
6770
<CssBaseline />
68-
<Stack direction={"row"}>
69-
<Box p={2} sx={{ width: "275px" }}>
71+
<Box sx={{ display: "flex", height: "100vh" }}>
72+
<Box
73+
sx={{
74+
width: "275px",
75+
flexShrink: 0,
76+
height: "100%",
77+
bgcolor: "secondary.darkest",
78+
borderRight: "1px solid",
79+
borderRightColor: "secondary.dark",
80+
}}
81+
>
82+
<img
83+
src={logo}
84+
alt="logo"
85+
style={{
86+
width: "160px",
87+
height: "auto",
88+
margin: "20px auto",
89+
display: "block",
90+
}}
91+
/>
7092
<SidePanel
7193
items={panelData?.data || []}
7294
onItemClick={handlePanelItemClick}
@@ -76,26 +98,40 @@ function App() {
7698
}}
7799
/>
78100
</Box>
79-
<Box p={2} sx={{ textAlign: "center", width: "80vw" }}>
80-
<MuiChipsInput
81-
value={chips}
82-
onChange={handleManualClauseChange}
83-
fullWidth
84-
/>
85-
<InventoryTable
86-
rows={tableData?.data || []}
87-
columns={columns}
88-
loading={loading}
89-
filterModel={filterModel}
90-
paginationModel={paginationModel}
91-
sortModel={sortModel}
92-
rowCount={rowCount}
93-
onFilterModelChange={handleFilterModelChange}
94-
onPaginationModelChange={setPaginationModel}
95-
onSortModelChange={setSortModel}
96-
/>
101+
<Box
102+
sx={{
103+
display: "flex",
104+
flexDirection: "column",
105+
flex: 1,
106+
overflow: "hidden",
107+
}}
108+
>
109+
<Box sx={{ flexShrink: 0, p: 2 }}>
110+
<MuiChipsInput
111+
size="small"
112+
value={chips}
113+
onChange={handleManualClauseChange}
114+
fullWidth
115+
/>
116+
</Box>
117+
<Box sx={{ flex: 1, overflow: "hidden" }}>
118+
<InventoryTable
119+
rows={tableData?.data || []}
120+
columns={columns}
121+
loading={loading}
122+
filterModel={filterModel}
123+
paginationModel={paginationModel}
124+
sortModel={sortModel}
125+
rowCount={rowCount}
126+
onFilterModelChange={handleFilterModelChange}
127+
onPaginationModelChange={setPaginationModel}
128+
onSortModelChange={setSortModel}
129+
onColumnVisibilityModelChange={setColumnVisibilityModel}
130+
columnVisibilityModel={columnVisibilityModel}
131+
/>
132+
</Box>
97133
</Box>
98-
</Stack>
134+
</Box>
99135
</ThemeProvider>
100136
);
101137
}

frontend/src/assets/logo.svg

Lines changed: 1 addition & 0 deletions
Loading

frontend/src/components/InventoryTable.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
GridSortModel,
77
DataGridPro as DataGrid,
88
gridClasses,
9+
GridColumnVisibilityModel,
910
} from "@mui/x-data-grid-pro";
1011
import "./InventoryTable.css";
1112
import { useEffect, useState } from "react";
@@ -18,9 +19,11 @@ interface InventoryTableProps {
1819
onFilterModelChange: (model: GridFilterModel) => void;
1920
onPaginationModelChange: (model: GridPaginationModel) => void;
2021
onSortModelChange: (model: GridSortModel) => void;
22+
onColumnVisibilityModelChange: (model: GridColumnVisibilityModel) => void;
2123
filterModel: any;
2224
paginationModel: GridPaginationModel;
2325
sortModel: GridSortModel;
26+
columnVisibilityModel: GridColumnVisibilityModel;
2427
rowCount?: number;
2528
}
2629

@@ -31,6 +34,8 @@ export const InventoryTable = ({
3134
onFilterModelChange,
3235
onPaginationModelChange,
3336
onSortModelChange,
37+
onColumnVisibilityModelChange,
38+
columnVisibilityModel,
3439
filterModel,
3540
paginationModel,
3641
sortModel,
@@ -79,9 +84,11 @@ export const InventoryTable = ({
7984
return (
8085
<>
8186
{loading ? (
82-
<Box sx={{ py: 2 }}>
83-
<CircularProgress color="success" disableShrink />
84-
</Box>
87+
<CircularProgress
88+
color="success"
89+
disableShrink
90+
sx={{ margin: "auto", display: "block", marginTop: "20px" }}
91+
/>
8592
) : columns.length === 0 ? (
8693
<Box
8794
sx={{
@@ -110,10 +117,13 @@ export const InventoryTable = ({
110117
paginationModel={paginationModel}
111118
sortModel={sortModel}
112119
filterModel={localFilterModel}
120+
columnVisibilityModel={columnVisibilityModel}
113121
onFilterModelChange={handleFilterModelChange}
114122
onPaginationModelChange={onPaginationModelChange}
115123
onSortModelChange={onSortModelChange}
124+
onColumnVisibilityModelChange={onColumnVisibilityModelChange}
116125
sx={{
126+
height: "100%",
117127
[`& .${gridClasses.cell}`]: {
118128
height: "52px",
119129
},
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.MuiListItemText-multiline {
22
display: flex;
3-
align-items: baseline;
3+
align-items: center;
44
gap: 10px;
55
}

0 commit comments

Comments
 (0)