Skip to content

Commit d974574

Browse files
Merge pull request #105 from NessieCanCode/add-date-selection-for-past-months
feat: allow selecting past months
2 parents 7e3d13f + 94c979e commit d974574

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This repository now includes a responsive Cockpit UI built with React. The inte
77
## ✅ Features
88

99
- **Monthly billing summaries** displayed right in Cockpit’s navigation menu.
10+
- **Selectable historical months** lets you view past billing periods for the current year while defaulting to the current month.
1011
- **Invoice dashboards** to view, download, and archive invoice PDFs.
1112
- **Detailed cost drill-downs** (core‑hours, instance‑hours, GB‑month) for per‑account transparency.
1213
- **Historical billing data** accessible from account inception for auditing and trend analysis.

src/slurmcostmanager.js

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,37 @@ const PLUGIN_BASE =
1212
window.cockpit.manifest.path) ||
1313
'/usr/share/cockpit/slurmcostmanager';
1414

15-
function getBillingPeriod(now = new Date()) {
16-
const end = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()));
17-
const start = new Date(Date.UTC(now.getFullYear(), now.getMonth(), 1));
15+
function getBillingPeriod(ref = new Date()) {
16+
const today = new Date();
17+
let year, month, end;
18+
if (typeof ref === 'string') {
19+
[year, month] = ref.split('-').map(Number);
20+
month -= 1;
21+
const isCurrent = year === today.getFullYear() && month === today.getMonth();
22+
end = isCurrent
23+
? new Date(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate()))
24+
: new Date(Date.UTC(year, month + 1, 0));
25+
} else {
26+
year = ref.getFullYear();
27+
month = ref.getMonth();
28+
end = new Date(Date.UTC(year, month, ref.getDate()));
29+
}
30+
const start = new Date(Date.UTC(year, month, 1));
1831
return {
1932
start: start.toISOString().slice(0, 10),
2033
end: end.toISOString().slice(0, 10)
2134
};
2235
}
2336

24-
function useBillingData() {
37+
function useBillingData(month) {
2538
const [data, setData] = useState(null);
2639
const [error, setError] = useState(null);
2740

2841
const load = useCallback(async () => {
2942
try {
3043
let json;
3144
if (window.cockpit && window.cockpit.spawn) {
32-
const { start, end } = getBillingPeriod();
45+
const { start, end } = getBillingPeriod(month);
3346
const args = [
3447
'python3',
3548
`${PLUGIN_BASE}/slurmdb.py`,
@@ -53,7 +66,7 @@ function useBillingData() {
5366
console.error(e);
5467
setError(e.message || String(e));
5568
}
56-
}, []);
69+
}, [month]);
5770

5871
useEffect(() => {
5972
load();
@@ -1049,8 +1062,18 @@ function Rates({ onRatesUpdated }) {
10491062

10501063
function App() {
10511064
const [view, setView] = useState('summary');
1052-
const { data, error, reload } = useBillingData();
1065+
const now = new Date();
1066+
const defaultMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(
1067+
2,
1068+
'0'
1069+
)}`;
1070+
const [month, setMonth] = useState(defaultMonth);
1071+
const { data, error, reload } = useBillingData(month);
10531072
const [showErrorDetails, setShowErrorDetails] = useState(false);
1073+
const monthOptions = Array.from(
1074+
{ length: now.getMonth() + 1 },
1075+
(_, i) => `${now.getFullYear()}-${String(i + 1).padStart(2, '0')}`
1076+
);
10541077

10551078
return React.createElement(
10561079
'div',
@@ -1074,6 +1097,23 @@ function App() {
10741097
'Settings'
10751098
)
10761099
),
1100+
view !== 'settings' &&
1101+
React.createElement(
1102+
'div',
1103+
{ className: 'month-select' },
1104+
React.createElement(
1105+
'label',
1106+
null,
1107+
'Month: ',
1108+
React.createElement(
1109+
'select',
1110+
{ value: month, onChange: e => setMonth(e.target.value) },
1111+
monthOptions.map(m =>
1112+
React.createElement('option', { key: m, value: m }, m)
1113+
)
1114+
)
1115+
)
1116+
),
10771117
view !== 'settings' && !data && !error && React.createElement('p', null, 'Loading...'),
10781118
view !== 'settings' &&
10791119
error &&

0 commit comments

Comments
 (0)