Skip to content

Commit 91d11af

Browse files
committed
feat: add in the files iframe
1 parent 4c4d951 commit 91d11af

File tree

18 files changed

+179
-1
lines changed

18 files changed

+179
-1
lines changed

api/backend/configs/commands.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ def create_config_file(filename: str, config: Schema):
4141
yaml.dump(filtered_config, f, default_flow_style=False, sort_keys=False)
4242

4343

44+
def read_yaml_file(filename: str):
45+
with open(filename, "r") as f:
46+
return yaml.load(f, Loader=yaml.FullLoader)
47+
48+
4449
def get_config_file_for_read(host: str):
4550
config = utils.read(f"./configs/{host}.yml")
4651
config.host.username = "user"

api/backend/configs/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from pydantic import BaseModel
2+
3+
4+
class AppConfig(BaseModel):
5+
files_url: str

api/backend/routers/config.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,19 @@
99
from api.backend.host_manager import HOST_MAP
1010
from api.backend.logging import LOG
1111

12+
from api.backend.configs.models import AppConfig
13+
1214
config_router = APIRouter()
1315

1416

17+
@config_router.get("/api/app-config")
18+
async def get_app_config():
19+
config = yaml_utils.read_yaml_file("./configs/app-config/app-config.yml")
20+
app_config = AppConfig(files_url=config["files_url"])
21+
22+
return JSONResponse(app_config.model_dump())
23+
24+
1525
@config_router.post("/api/config")
1626
async def create_config(build_config: BuildConfigFile):
1727
try:

src/app/store.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { configureStore } from "@reduxjs/toolkit";
22
import integrationsReducer from "@/lib/slices/integrations";
33
import settingsReducer from "@/lib/slices/settings";
4+
import appConfigReducer from "@/lib/slices/app-config";
45

56
export const store = configureStore({
67
reducer: {
8+
appConfig: appConfigReducer,
79
integrations: integrationsReducer,
810
settings: settingsReducer,
911
},
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"use client";
2+
3+
import { IconButton } from "@mui/material";
4+
import React, { useState, useEffect } from "react";
5+
import FindInPageIcon from "@mui/icons-material/FindInPage";
6+
import { useRouter } from "next/navigation";
7+
import { useAppConfig } from "@/lib/hooks/use-app-config";
8+
9+
export type FilesProps = {
10+
className?: string;
11+
};
12+
13+
export const Files = ({ className }: FilesProps) => {
14+
const router = useRouter();
15+
const { appConfig } = useAppConfig();
16+
const [isClient, setIsClient] = useState(false);
17+
18+
useEffect(() => {
19+
setIsClient(true);
20+
}, []);
21+
22+
if (!isClient) return null;
23+
24+
return appConfig.filesUrl ? (
25+
<div className={className}>
26+
<IconButton component="span" onClick={() => router.push("/files")}>
27+
<FindInPageIcon />
28+
</IconButton>
29+
</div>
30+
) : null;
31+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./files";

src/components/dashboard/dashboard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useEffect } from "react";
22
import { fetchAndSet } from "@/lib/utils";
3-
import { Container, Grid } from "@mui/material";
3+
import { Container } from "@mui/material";
44
import classes from "./dashboard.module.css";
55
import HostOverview from "@/components/shared/host-overview/host-overview";
66
import { useRouter } from "next/router";

src/lib/hooks/use-app-config.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { RootState } from "@/app";
2+
import { useSelector } from "react-redux";
3+
import { AppConfig } from "../services/app-config/app-config.types";
4+
import { setAppConfig } from "../slices/app-config";
5+
import { useDispatch } from "react-redux";
6+
7+
export const useAppConfig = () => {
8+
const dispatch = useDispatch();
9+
const appConfig = useSelector((state: RootState) => state.appConfig);
10+
11+
return {
12+
appConfig,
13+
setNewAppConfig: (appConfig: AppConfig) =>
14+
dispatch(setAppConfig(appConfig)),
15+
};
16+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export type ServerAppConfig = {
2+
files_url: string;
3+
};
4+
5+
export type AppConfig = {
6+
filesUrl: string;
7+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./read-config";
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { apiGet } from "@/lib/utils";
2+
import { ServerAppConfig } from "../app-config.types";
3+
4+
const parseAppConfig = (appConfig: ServerAppConfig) => {
5+
return {
6+
filesUrl: appConfig.files_url,
7+
};
8+
};
9+
10+
export const getAppConfig = async () => {
11+
const appConfig: ServerAppConfig = await apiGet("/api/app-config");
12+
13+
return parseAppConfig(appConfig);
14+
};

src/lib/services/app-config/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as AppConfig from "./functions";
2+
3+
export { AppConfig };

src/lib/slices/app-config.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2+
import { AppConfig } from "../services/app-config/app-config.types";
3+
4+
const loadFromLocalStorage = () => {
5+
try {
6+
const serializedState = localStorage.getItem("appConfig");
7+
if (serializedState === null) return undefined;
8+
return JSON.parse(serializedState);
9+
} catch (e) {
10+
console.error("Could not load from localStorage:", e);
11+
return undefined;
12+
}
13+
};
14+
15+
const saveToLocalStorage = (state: AppConfig) => {
16+
try {
17+
const serializedState = JSON.stringify(state);
18+
localStorage.setItem("appConfig", serializedState);
19+
} catch (e) {
20+
console.error("Could not save to localStorage:", e);
21+
}
22+
};
23+
24+
const initialState: AppConfig = loadFromLocalStorage() || {
25+
filesUrl: "",
26+
};
27+
28+
const appConfigSlice = createSlice({
29+
name: "appConfig",
30+
initialState,
31+
reducers: {
32+
setAppConfig: (state, action: PayloadAction<AppConfig>) => {
33+
saveToLocalStorage({ ...state, ...action.payload });
34+
return { ...state, ...action.payload };
35+
},
36+
},
37+
});
38+
39+
export const { setAppConfig } = appConfigSlice.actions;
40+
41+
export default appConfigSlice.reducer;

src/lib/slices/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
export * from "./integrations";
2+
export * from "./app-config";
3+
export * from "./settings";

src/pages/_app.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { ToastContainer } from "react-toastify";
1515
import { Provider } from "react-redux";
1616
import { store } from "@/app";
1717
import { BackgroundChanger } from "@/components/dashboard/controls";
18+
import { Files } from "@/components/dashboard/controls/files";
1819

1920
const App: React.FC<AppProps> = ({ Component, pageProps }) => {
2021
const [isDarkMode, setIsDarkMode] = useState(false);
@@ -59,6 +60,7 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
5960
<div className="global-controls">
6061
<BackgroundChanger className="global-control" />
6162
<SettingsControl className="global-control" />
63+
<Files className="global-control" />
6264
</div>
6365
<Box
6466
className="mainWrapper"

src/pages/api/app-config.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type { NextApiRequest, NextApiResponse } from "next";
2+
import { cacheApi } from "@/lib/services/api";
3+
import { ServerAppConfig } from "@/lib/services/app-config/app-config.types";
4+
5+
export default async function handler(
6+
_: NextApiRequest,
7+
res: NextApiResponse<ServerAppConfig>
8+
) {
9+
const response = await cacheApi.get<ServerAppConfig>("/app-config");
10+
res.status(200).json(response.data);
11+
}

src/pages/files.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"use client";
2+
3+
import { useAppConfig } from "@/lib/hooks/use-app-config";
4+
5+
const IframeComponent = () => {
6+
const { appConfig } = useAppConfig();
7+
8+
if (!appConfig.filesUrl) {
9+
return null;
10+
}
11+
12+
return (
13+
<iframe
14+
src={appConfig.filesUrl}
15+
style={{ width: "100%", height: "100%", border: "none" }}
16+
title="Files"
17+
/>
18+
);
19+
};
20+
21+
export default IframeComponent;

src/pages/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ import { store } from "@/app";
44
import { setIntegrations } from "@/lib/slices/integrations";
55
import { apiCaller } from "@/lib/services/api-caller";
66
import { Integration } from "@/lib/types";
7+
import { AppConfig } from "@/lib/services/app-config";
8+
import { setAppConfig } from "@/lib/slices";
79

810
const Home = () => {
911
React.useEffect(() => {
1012
apiCaller.integrations().then((res) => {
1113
store.dispatch(setIntegrations(res as Integration[]));
1214
});
15+
16+
AppConfig.getAppConfig().then((res) => {
17+
store.dispatch(setAppConfig(res));
18+
});
1319
}, []);
1420

1521
return <Dashboard />;

0 commit comments

Comments
 (0)