Skip to content

Commit 5cacf23

Browse files
committed
fix: global settings, color changing background, argocd integration
1 parent 5c11a27 commit 5cacf23

File tree

42 files changed

+493
-26
lines changed

Some content is hidden

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

42 files changed

+493
-26
lines changed

api/backend/integrations/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .integration import INTEGRATIONS
66
from .qbittorrent import get_transfer_info
77
from .uptime_kuma import get_uptime
8+
from .argocd import get_argocd_data
89

910
__all__ = [
1011
"INTEGRATIONS",
@@ -13,4 +14,5 @@
1314
"get_jellyfin_data",
1415
"get_movies",
1516
"get_shows",
17+
"get_argocd_data",
1618
]

api/backend/integrations/apps.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ class Apps(Enum):
88
SONARR = "sonarr"
99
QBITTORRENT = "qbittorrent"
1010
KUMA = "kuma"
11+
ARGOCD = "argocd"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .integration import get_argocd_data
2+
3+
__all__ = ["get_argocd_data"]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import requests
2+
from typing import Any
3+
4+
from api.backend.integrations.integration import INTEGRATIONS
5+
6+
argocd_integration = next(
7+
(integration for integration in INTEGRATIONS if integration.name == "argocd"),
8+
None,
9+
)
10+
11+
12+
def get_auth_token() -> str:
13+
assert argocd_integration is not None
14+
15+
payload = {
16+
"username": argocd_integration.config["username"],
17+
"password": argocd_integration.config["password"],
18+
}
19+
20+
response = requests.post(
21+
f"{argocd_integration.config['url']}/api/v1/session", json=payload
22+
)
23+
24+
return response.json()["token"]
25+
26+
27+
def get_applications() -> list[dict[str, Any]]:
28+
assert argocd_integration is not None
29+
30+
response = requests.get(
31+
f"{argocd_integration.config['url']}/api/v1/applications",
32+
headers={"Authorization": f"Bearer {get_auth_token()}"},
33+
)
34+
35+
return response.json()["items"]
36+
37+
38+
def format_application_data(application: dict[str, Any]) -> dict[str, Any]:
39+
metadata = application["metadata"]
40+
status = application["status"]
41+
42+
return {
43+
"name": metadata["name"],
44+
"status": status["sync"]["status"],
45+
}
46+
47+
48+
def get_argocd_data() -> list[dict[str, Any]]:
49+
applications = get_applications()
50+
51+
return [format_application_data(application) for application in applications]

api/backend/routers/integration.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
get_uptime,
1616
get_jellyfin_data,
1717
get_transfer_info,
18+
get_argocd_data,
1819
)
1920

2021
LOG = logging.getLogger(__name__)
@@ -64,3 +65,8 @@ async def get_radarr_movie_count():
6465
@integration_router.get("/api/integrations/sonarr/shows")
6566
async def get_sonarr_show_count():
6667
return await get_shows()
68+
69+
70+
@integration_router.get("/api/integrations/argocd/applications")
71+
def get_argocd_applications():
72+
return get_argocd_data()

package-lock.json

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

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@testing-library/react": "^13.4.0",
1414
"@testing-library/user-event": "^13.5.0",
1515
"@types/formidable": "^3.4.5",
16+
"@types/react-color": "^3.0.13",
1617
"axios": "^1.7.8",
1718
"axios-cache-interceptor": "^1.6.2",
1819
"bootstrap": "^5.3.0",
@@ -23,6 +24,7 @@
2324
"qbittorrent-api-v2": "^1.2.2",
2425
"react": "^18.3.1",
2526
"react-bootstrap": "^2.8.0",
27+
"react-color": "^2.19.3",
2628
"react-dom": "^18.3.1",
2729
"react-markdown": "^9.0.0",
2830
"react-modal-image": "^2.6.0",

public/icons/argocd.png

235 KB
Loading

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";
3+
import settingsReducer from "@/lib/slices/settings";
34

45
export const store = configureStore({
56
reducer: {
67
integrations: integrationsReducer,
8+
settings: settingsReducer,
79
},
810
});
911

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./settings-control";
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { IconButton } from "@mui/material";
2+
import SettingsIcon from "@mui/icons-material/Settings";
3+
import React, { useState } from "react";
4+
import { SettingsMenu } from "../settings-menu";
5+
6+
export type SettingsControlProps = {
7+
className?: string;
8+
};
9+
10+
export const SettingsControl = ({ className }: SettingsControlProps) => {
11+
const [open, setOpen] = useState<boolean>(false);
12+
13+
return (
14+
<div className={className}>
15+
<label htmlFor="settings-menu">
16+
<IconButton component="span" onClick={() => setOpen(true)}>
17+
<SettingsIcon />
18+
</IconButton>
19+
</label>
20+
<SettingsMenu open={open} onClose={() => setOpen(false)} />
21+
</div>
22+
);
23+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./settings-menu";

src/components/dashboard/controls/settings/settings-menu/settings-menu.module.css

Whitespace-only changes.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Dialog, DialogTitle, DialogContent } from "@mui/material";
2+
import React, { useState } from "react";
3+
import { ColorResult, SketchPicker } from "react-color";
4+
import { useGetSettings } from "@/lib/hooks/useGetSettings";
5+
import { setSettings } from "@/lib/slices/settings";
6+
import { useDispatch } from "react-redux";
7+
import { Divider } from "@mui/material";
8+
9+
export type SettingsMenuProps = {
10+
open: boolean;
11+
onClose: () => void;
12+
};
13+
14+
export const SettingsMenu = ({ open, onClose }: SettingsMenuProps) => {
15+
const settings = useGetSettings();
16+
const dispatch = useDispatch();
17+
const [color, setColor] = useState({ hex: settings.cardColor });
18+
19+
const handleChange = (color: ColorResult) => {
20+
setColor(color);
21+
dispatch(setSettings({ cardColor: `${color.hex}85` }));
22+
};
23+
24+
return (
25+
<Dialog open={open} onClose={onClose}>
26+
<DialogTitle className="text-2xl font-bold">Settings</DialogTitle>
27+
<DialogContent>
28+
<div className="flex flex-col gap-2">
29+
<span className="text-sm font-medium">Card Colors</span>
30+
<Divider />
31+
<SketchPicker
32+
className="w-[20rem]"
33+
color={color.hex}
34+
onChange={handleChange}
35+
onChangeComplete={handleChange}
36+
/>
37+
</div>
38+
</DialogContent>
39+
</Dialog>
40+
);
41+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.applications {
2+
display: flex;
3+
flex-direction: column;
4+
gap: 0.5rem;
5+
}
6+
7+
.application {
8+
background-color: var(--integration-bg-color);
9+
padding: 0.125rem;
10+
border-radius: 0.125rem;
11+
12+
width: 100%;
13+
text-align: center;
14+
15+
display: flex;
16+
gap: 0.25rem;
17+
18+
align-items: center;
19+
justify-content: center;
20+
}
21+
22+
.applicationStatus {
23+
font-family: monospace;
24+
padding: 0.125rem;
25+
border-radius: 0.125rem;
26+
}
27+
28+
.synced {
29+
background-color: var(--synced);
30+
}
31+
32+
.outOfSync {
33+
background-color: var(--outOfSync);
34+
}

0 commit comments

Comments
 (0)