Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
cd59cff
feat: add Assets page with summary tiles and table
Abhishek-Punhani Feb 8, 2026
fc303f6
feat: enhance asset details and summary tiles with additional metrics…
Abhishek-Punhani Feb 8, 2026
94bf7b1
feat(assets): enhance billing dashboard with auto-refresh and cost chart
Abhishek-Punhani Feb 8, 2026
3edf17b
feat: add dashboard view and visualization components for asset manag…
Abhishek-Punhani Feb 8, 2026
42d1644
feat(assets): enhance daily cost breakdown and trend components with …
Abhishek-Punhani Feb 8, 2026
9cb6fb6
feat(assets): update styling for summary tiles and improve layout con…
Abhishek-Punhani Feb 8, 2026
f957cb7
feat: implement responsive sidebar navigation with theme toggle
Abhishek-Punhani Feb 8, 2026
195473f
feat: enhance sidebar navigation with responsive design and theme han…
Abhishek-Punhani Feb 8, 2026
0948816
improved the sidebar responsiveness
Abhishek-Punhani Feb 8, 2026
e3f2e2c
feat: enhance dark mode styling for MUI components and improve asset …
Abhishek-Punhani Feb 9, 2026
a19f807
feat: integrate Carbon Design System components and styles
Abhishek-Punhani Feb 9, 2026
2b3f142
feat: enhance theme variables and sidebar styles for improved dark mo…
Abhishek-Punhani Feb 9, 2026
eed6a0e
feat: add allocation service with mock data fallback
Abhishek-Punhani Feb 9, 2026
feda400
feat: add AllocationSkeleton component and enhance loading states in …
Abhishek-Punhani Feb 9, 2026
5126e0a
feat: refactor Header component and unify header styles across pages
Abhishek-Punhani Feb 9, 2026
bc814f6
modularising code - Allocations Page
Abhishek-Punhani Feb 9, 2026
c36290d
feat: add AssetsFilterBar, AssetsHeaderControls, and AssetsNotificati…
Abhishek-Punhani Feb 9, 2026
4024c29
feat: update styles for dropdowns and tables; enhance loading states …
Abhishek-Punhani Feb 9, 2026
3362397
feat: enhance data handling in AllocationCostChart and AllocationDeta…
Abhishek-Punhani Feb 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
557 changes: 529 additions & 28 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
],
"dependencies": {
"@babel/runtime": "^7.28.6",
"@carbon/react": "^1.100.0",
"@date-io/core": "^3.2.0",
"@date-io/date-fns": "^3.2.1",
"@emotion/react": "^11.14.0",
Expand Down Expand Up @@ -42,6 +43,7 @@
"parcel": "^2.16.3",
"prettier": "^3.8.0",
"process": "^0.11.10",
"sass": "^1.97.3",
"set-value": "4.1.0"
},
"resolutions": {
Expand Down
2 changes: 2 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { createRoot } from "react-dom/client";
import Routes from "./route";
import "@carbon/styles/css/styles.min.css";
import "./css/index.css";

const root = createRoot(document.getElementById("app"));
root.render(<Routes />);
116 changes: 116 additions & 0 deletions src/components/AllocationSkeleton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React from "react";

/**
* AllocationSkeleton — shimmer placeholder that mirrors the Allocations page layout.
* Shows skeleton tiles, a chart area, and table rows.
*/
const AllocationSkeleton = () => {
return (
<div
className="skeleton-wrap"
aria-busy="true"
aria-label="Loading allocations"
>
{/* ── Title skeleton ── */}
<div style={{ marginBottom: "16px" }}>
<div
className="skeleton-line skeleton-line--md"
style={{ marginBottom: 8 }}
/>
<div className="skeleton-line skeleton-line--xs" />
</div>

{/* ── Summary tile skeletons ── */}
<div
className="skeleton-tiles"
style={{ gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))" }}
>
{[1, 2, 3, 4, 5, 6].map((i) => (
<div
key={i}
className="skeleton-tile"
style={{ borderRadius: 10, padding: "16px 18px" }}
>
<div className="skeleton-line skeleton-line--sm" />
<div
className="skeleton-line"
style={{ width: "100px", height: "22px", borderRadius: 6 }}
/>
</div>
))}
</div>

{/* ── Chart skeleton ── */}
<div className="skeleton-chart">
<div className="skeleton-chart-header">
<div className="skeleton-line skeleton-line--md" />
<div className="skeleton-line skeleton-line--xs" />
</div>
<div className="skeleton-chart-body">
<div className="skeleton-bars">
{[55, 75, 40, 65, 85, 50, 70, 60, 80, 45, 72, 38].map((h, i) => (
<div
key={i}
className="skeleton-bar"
style={{ height: `${h}%` }}
/>
))}
</div>
</div>
</div>

{/* ── Table skeleton ── */}
<div className="skeleton-table" style={{ borderRadius: 8 }}>
{/* Toolbar */}
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "10px 14px",
borderBottom: "1px solid var(--border-light, #f0f0f0)",
}}
>
<div
className="skeleton-line"
style={{ width: 200, height: 28, borderRadius: 6 }}
/>
<div className="skeleton-line skeleton-line--sm" />
</div>
{/* Header */}
<div
className="skeleton-table-header"
style={{
gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr 1fr 1fr 0.6fr 1fr",
}}
>
{[1, 2, 3, 4, 5, 6, 7, 8, 9].map((i) => (
<div key={i} className="skeleton-line skeleton-line--col" />
))}
</div>
{/* Rows */}
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((row) => (
<div
key={row}
className="skeleton-table-row"
style={{
gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr 1fr 1fr 0.6fr 1fr",
}}
>
<div className="skeleton-line skeleton-line--name" />
<div className="skeleton-line skeleton-line--sm" />
<div className="skeleton-line skeleton-line--sm" />
<div className="skeleton-line skeleton-line--sm" />
<div className="skeleton-line skeleton-line--sm" />
<div className="skeleton-line skeleton-line--sm" />
<div className="skeleton-line skeleton-line--sm" />
<div className="skeleton-line skeleton-line--pill" />
<div className="skeleton-line skeleton-line--sm skeleton-line--right" />
</div>
))}
</div>
</div>
);
};

export default AllocationSkeleton;
20 changes: 13 additions & 7 deletions src/components/Footer.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { Parser as HtmlToReactParser } from "html-to-react";

// Footer could be HTML, so we need to parse it.
const Footer = () => {
const content = '<div align="right"><br/>PLACEHOLDER_FOOTER_CONTENT</div>';
const htmlToReactParser = new HtmlToReactParser();
const parsedContent = htmlToReactParser.parse(content);
return parsedContent;
return (
<div
className="footer-content"
style={{
textAlign: "right",
padding: "1rem",
color: "#888",
fontSize: "12px",
}}
>
OpenCost UI
</div>
);
};

export default Footer;
29 changes: 13 additions & 16 deletions src/components/Header.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
import Breadcrumbs from "@mui/material/Breadcrumbs";
import Link from "@mui/material/Link";
import Typography from "@mui/material/Typography";
import ThemeToggle from "./ThemeToggle";

const Header = (props) => {
const { title, breadcrumbs, headerTitle } = props;

return (
<div
style={{
alignItems: "center",
display: "flex",
flexFlow: "row",
width: "100%",
marginTop: "10px",
}}
>
<Typography variant="h3" style={{ marginBottom: "10px" }}>
{headerTitle}
</Typography>
<div style={{ flex: "1 0 auto" }}>
{title && <Typography variant="h4">{title}</Typography>}
<div className="page-header">
<div className="page-header__left">
<h1 className="page-header__title">{headerTitle}</h1>
{title && <span className="page-header__subtitle">{title}</span>}
{breadcrumbs && breadcrumbs.length > 0 && (
<Breadcrumbs aria-label="breadcrumb">
<Breadcrumbs
aria-label="breadcrumb"
className="page-header__breadcrumbs"
>
{breadcrumbs.slice(0, breadcrumbs.length - 1).map((b) => (
<Link color="inherit" href={b.href} key={b.name}>
{b.name}
Expand All @@ -33,7 +27,10 @@ const Header = (props) => {
</Breadcrumbs>
)}
</div>
<div style={{ flex: "0 0 auto" }}>{props.children}</div>
<div className="page-header__right">
<ThemeToggle />
{props.children}
</div>
</div>
);
};
Expand Down
51 changes: 47 additions & 4 deletions src/components/Nav/NavItem.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
import { ListItem, ListItemIcon, ListItemText } from "@mui/material";
import { Link } from "react-router";
import * as React from "react";

const NavItem = ({ active, href, name, onClick, secondary, title, icon }) => {
const [theme, setTheme] = React.useState(
document.documentElement.getAttribute("data-theme") || "light",
);

React.useEffect(() => {
const observer = new MutationObserver(() => {
const newTheme =
document.documentElement.getAttribute("data-theme") || "light";
setTheme(newTheme);
});

observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["data-theme"],
});

return () => observer.disconnect();
}, []);

const isDark = theme === "dark";

const renderListItemCore = () => (
<ListItem
className={active ? "active" : ""}
sx={{
"&.MuiListItem-root": {
borderRadius: "8px",
margin: "2px 8px",
transition: "all 0.2s ease",
},
"&.MuiListItem-root:hover": {
backgroundColor: "#ebebeb",
backgroundColor: isDark ? "var(--sidebar-hover)" : "#f0f0f0",
},
"&.MuiListItem-root.active": {
backgroundColor: "#e1e1e1",
backgroundColor: isDark ? "var(--sidebar-active)" : "#e8f0ff",
},
}}
onClick={(e) => {
Expand All @@ -24,8 +51,15 @@ const NavItem = ({ active, href, name, onClick, secondary, title, icon }) => {
<ListItemIcon
sx={{
"&.MuiListItemIcon-root": {
color: active ? "#346ef2" : "#4e4e4e",
color: active
? isDark
? "var(--accent-primary)"
: "#0f62fe"
: isDark
? "var(--text-secondary)"
: "#5a5a5a",
minWidth: 36,
transition: "color 0.2s ease",
},
}}
>
Expand All @@ -34,7 +68,16 @@ const NavItem = ({ active, href, name, onClick, secondary, title, icon }) => {
<ListItemText
sx={{
"& .MuiListItemText-primary": {
color: active ? "#346ef2" : "inherit",
color: active
? isDark
? "var(--accent-primary)"
: "#0f62fe"
: isDark
? "var(--text-primary)"
: "inherit",
fontWeight: active ? 600 : 400,
fontSize: "0.9375rem",
transition: "color 0.2s ease",
},
}}
primary={name}
Expand Down
Loading