Compare commits

..

4 Commits

Author SHA1 Message Date
Elisiário Couto
e9924e9d96 chore(ci): Bump version to 2025.9.19 2025-09-22 00:38:36 +01:00
copilot-swe-agent[bot]
340e1a3235 feat(frontend): Add version display in header near connection status
Co-authored-by: elisiariocouto <818914+elisiariocouto@users.noreply.github.com>
2025-09-22 00:36:36 +01:00
copilot-swe-agent[bot]
4ce56fdc04 fix(frontend): Resolve mobile horizontal scroll in Time Period filters
Co-authored-by: elisiariocouto <818914+elisiariocouto@users.noreply.github.com>
2025-09-21 23:52:42 +01:00
copilot-swe-agent[bot]
dd24a0e0d3 fix(frontend): Close mobile sidebar on navigation item click
Co-authored-by: elisiariocouto <818914+elisiariocouto@users.noreply.github.com>
2025-09-21 23:39:43 +01:00
8 changed files with 84 additions and 6 deletions

View File

@@ -1,4 +1,32 @@
## 2025.9.19 (2025/09/21)
### Bug Fixes
- **frontend:** Close mobile sidebar on navigation item click ([dd24a0e0](https://github.com/elisiariocouto/leggen/commit/dd24a0e0d34c3b2ff37bc75b50162768b4d15cc5))
- **frontend:** Resolve mobile horizontal scroll in Time Period filters ([4ce56fdc](https://github.com/elisiariocouto/leggen/commit/4ce56fdc042b0dbf3442a1ab201392700add90d6))
### Features
- **frontend:** Add version display in header near connection status ([340e1a32](https://github.com/elisiariocouto/leggen/commit/340e1a3235916566a4e403e9ec7b82ea799fbffd))
## 2025.9.19 (2025/09/21)
### Bug Fixes
- **frontend:** Close mobile sidebar on navigation item click ([dd24a0e0](https://github.com/elisiariocouto/leggen/commit/dd24a0e0d34c3b2ff37bc75b50162768b4d15cc5))
- **frontend:** Resolve mobile horizontal scroll in Time Period filters ([4ce56fdc](https://github.com/elisiariocouto/leggen/commit/4ce56fdc042b0dbf3442a1ab201392700add90d6))
### Features
- **frontend:** Add version display in header near connection status ([340e1a32](https://github.com/elisiariocouto/leggen/commit/340e1a3235916566a4e403e9ec7b82ea799fbffd))
## 2025.9.18 (2025/09/19) ## 2025.9.18 (2025/09/19)
### Documentation ### Documentation

View File

@@ -27,6 +27,7 @@ import {
SidebarGroup, SidebarGroup,
SidebarGroupContent, SidebarGroupContent,
SidebarGroupLabel, SidebarGroupLabel,
useSidebar,
} from "./ui/sidebar"; } from "./ui/sidebar";
const navigation = [ const navigation = [
@@ -39,6 +40,7 @@ const navigation = [
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) { export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const location = useLocation(); const location = useLocation();
const [accountsExpanded, setAccountsExpanded] = useState(false); const [accountsExpanded, setAccountsExpanded] = useState(false);
const { isMobile, setOpenMobile } = useSidebar();
const { data: accounts } = useQuery<Account[]>({ const { data: accounts } = useQuery<Account[]>({
queryKey: ["accounts"], queryKey: ["accounts"],
@@ -51,6 +53,13 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
return sum + primaryBalance; return sum + primaryBalance;
}, 0) || 0; }, 0) || 0;
// Handler to close mobile sidebar when navigation item is clicked
const handleNavigationClick = () => {
if (isMobile) {
setOpenMobile(false);
}
};
return ( return (
<Sidebar collapsible="icon" className="pt-safe-top pl-safe-left" {...props}> <Sidebar collapsible="icon" className="pt-safe-top pl-safe-left" {...props}>
<SidebarHeader> <SidebarHeader>
@@ -60,7 +69,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
asChild asChild
className="data-[slot=sidebar-menu-button]:!p-1.5" className="data-[slot=sidebar-menu-button]:!p-1.5"
> >
<Link to="/" className="flex items-center space-x-2"> <Link to="/" className="flex items-center space-x-2" onClick={handleNavigationClick}>
<Logo size={24} /> <Logo size={24} />
<span className="text-base font-semibold">Leggen</span> <span className="text-base font-semibold">Leggen</span>
</Link> </Link>
@@ -80,7 +89,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
tooltip={item.name} tooltip={item.name}
isActive={location.pathname === item.to} isActive={location.pathname === item.to}
> >
<Link to={item.to}> <Link to={item.to} onClick={handleNavigationClick}>
<item.icon className="h-5 w-5" /> <item.icon className="h-5 w-5" />
<span>{item.name}</span> <span>{item.name}</span>
</Link> </Link>

View File

@@ -30,6 +30,17 @@ export function SiteHeader() {
refetchInterval: 30000, refetchInterval: 30000,
}); });
const {
data: versionData,
isLoading: versionLoading,
isError: versionError,
} = useQuery({
queryKey: ["version"],
queryFn: apiClient.getVersion,
refetchInterval: 5 * 60 * 1000, // Refetch version every 5 minutes
retry: 1, // Only retry once since version is less critical
});
return ( return (
<header className="flex h-16 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear pt-safe-top"> <header className="flex h-16 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear pt-safe-top">
<div className="flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6"> <div className="flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6">
@@ -43,6 +54,20 @@ export function SiteHeader() {
</h1> </h1>
<div className="ml-auto flex items-center space-x-3"> <div className="ml-auto flex items-center space-x-3">
{/* Version display */}
<div className="flex items-center space-x-1">
{versionLoading ? (
<span className="text-xs text-muted-foreground">v...</span>
) : versionError || !versionData ? (
<span className="text-xs text-muted-foreground">v?</span>
) : (
<span className="text-xs text-muted-foreground">
v{versionData.version}
</span>
)}
</div>
{/* Connection status */}
<div className="flex items-center space-x-1"> <div className="flex items-center space-x-1">
{healthLoading ? ( {healthLoading ? (
<> <>

View File

@@ -15,12 +15,12 @@ export default function TimePeriodFilter({
className = "", className = "",
}: TimePeriodFilterProps) { }: TimePeriodFilterProps) {
return ( return (
<div className={`flex items-center gap-4 ${className}`}> <div className={`flex flex-col sm:flex-row sm:items-center gap-4 ${className}`}>
<div className="flex items-center gap-2 text-foreground"> <div className="flex items-center gap-2 text-foreground">
<Calendar size={20} /> <Calendar size={20} />
<span className="font-medium">Time Period:</span> <span className="font-medium">Time Period:</span>
</div> </div>
<div className="flex gap-2"> <div className="flex flex-wrap gap-2">
{TIME_PERIODS.map((period) => ( {TIME_PERIODS.map((period) => (
<Button <Button
key={period.value} key={period.value}

View File

@@ -10,6 +10,7 @@ import type {
NotificationService, NotificationService,
NotificationServicesResponse, NotificationServicesResponse,
HealthData, HealthData,
VersionData,
AccountUpdate, AccountUpdate,
TransactionStats, TransactionStats,
} from "../types/api"; } from "../types/api";
@@ -167,6 +168,15 @@ export const apiClient = {
return response.data.data; return response.data.data;
}, },
// Get version information
getVersion: async (): Promise<VersionData> => {
// Use the root endpoint (/) which provides version information
const response = await api.get<VersionData>("/", {
baseURL: import.meta.env.VITE_API_URL?.replace('/api/v1', '') || '',
});
return response.data;
},
// Analytics endpoints // Analytics endpoints
getTransactionStats: async (days?: number): Promise<TransactionStats> => { getTransactionStats: async (days?: number): Promise<TransactionStats> => {
const queryParams = new URLSearchParams(); const queryParams = new URLSearchParams();

View File

@@ -201,6 +201,12 @@ export interface HealthData {
error?: string; error?: string;
} }
// Version information from root endpoint
export interface VersionData {
message: string;
version: string;
}
// Analytics data types // Analytics data types
export interface TransactionStats { export interface TransactionStats {
period_days: number; period_days: number;

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "leggen" name = "leggen"
version = "2025.9.18" version = "2025.9.19"
description = "An Open Banking CLI" description = "An Open Banking CLI"
authors = [{ name = "Elisiário Couto", email = "elisiario@couto.io" }] authors = [{ name = "Elisiário Couto", email = "elisiario@couto.io" }]
requires-python = "~=3.13.0" requires-python = "~=3.13.0"

2
uv.lock generated
View File

@@ -220,7 +220,7 @@ wheels = [
[[package]] [[package]]
name = "leggen" name = "leggen"
version = "2025.9.18" version = "2025.9.19"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "apscheduler" }, { name = "apscheduler" },