Compare commits
4
Commits
f8c6e38841
...
e637c5ac60
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e637c5ac60 | ||
|
|
c71ae4285a | ||
|
|
c248e67304 | ||
|
|
628114ad91 |
+1
-1
@@ -132,7 +132,7 @@ def main(
|
|||||||
days=days[:5],
|
days=days[:5],
|
||||||
balance_offset=2,
|
balance_offset=2,
|
||||||
workers_required=1,
|
workers_required=1,
|
||||||
constraints=[MaxShiftsPerWeekConstraint(max_shifts=1)],
|
constraints=[MaxShiftsPerWeekConstraint(max_shifts=2)],
|
||||||
),
|
),
|
||||||
SingleShift(
|
SingleShift(
|
||||||
sites=(
|
sites=(
|
||||||
|
|||||||
@@ -1729,6 +1729,16 @@ function syntaxHighlight(json) {
|
|||||||
const mainTable = document.getElementById("main-table");
|
const mainTable = document.getElementById("main-table");
|
||||||
if (!mainTable) return;
|
if (!mainTable) return;
|
||||||
|
|
||||||
|
// Ensure the header row is inside a proper <thead> element.
|
||||||
|
// Some exports use a bare <tr> as the first row; move it into a thead so CSS/sticky headers work.
|
||||||
|
if (!mainTable.tHead) {
|
||||||
|
const firstRow = mainTable.querySelector('tr');
|
||||||
|
if (firstRow) {
|
||||||
|
const thead = mainTable.createTHead();
|
||||||
|
thead.appendChild(firstRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper to remove highlight from all headers
|
// Helper to remove highlight from all headers
|
||||||
function clearColHover() {
|
function clearColHover() {
|
||||||
const ths = mainTable.querySelectorAll("th.col-hover");
|
const ths = mainTable.querySelectorAll("th.col-hover");
|
||||||
@@ -1763,6 +1773,18 @@ $("#main-table").before(
|
|||||||
`<button id="show-display-settings" style="margin:8px 0 8px 0; float:right;">Display Settings</button>`
|
`<button id="show-display-settings" style="margin:8px 0 8px 0; float:right;">Display Settings</button>`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Ensure main table header is sticky and compact
|
||||||
|
if ($('#main-table-style').length === 0) {
|
||||||
|
$('head').append(`
|
||||||
|
<style id='main-table-style'>
|
||||||
|
/* Make main timetable header sticky */
|
||||||
|
#main-table thead th, #main-table thead td { position: sticky; top: 0; z-index: 60; background: #fff; font-size: 12px; }
|
||||||
|
/* Slight shadow to separate header from body */
|
||||||
|
#main-table thead th { box-shadow: 0 2px 6px rgba(0,0,0,0.06); }
|
||||||
|
</style>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
// --- Modal show/hide logic ---
|
// --- Modal show/hide logic ---
|
||||||
$("#show-display-settings").on("click", function() {
|
$("#show-display-settings").on("click", function() {
|
||||||
$("#display-settings-modal").show();
|
$("#display-settings-modal").show();
|
||||||
|
|||||||
@@ -5222,8 +5222,10 @@ class RotaBuilder(object):
|
|||||||
|
|
||||||
timetable = []
|
timetable = []
|
||||||
|
|
||||||
|
# Run times and heading go outside the table; store for later insertion
|
||||||
|
run_times_html = ""
|
||||||
if self.run_start_time is not None and self.run_end_time is not None:
|
if self.run_start_time is not None and self.run_end_time is not None:
|
||||||
timetable.append(
|
run_times_html = (
|
||||||
"<div id='run_times_row' style='display: flex; gap: 2em; margin-bottom: 1em;'>"
|
"<div id='run_times_row' style='display: flex; gap: 2em; margin-bottom: 1em;'>"
|
||||||
f"<div id='run_start_time_cell'>Start time: <span id='run_start_time'>{self.run_start_time:%Y-%m-%d %H:%M:%S%z}</span></div>"
|
f"<div id='run_start_time_cell'>Start time: <span id='run_start_time'>{self.run_start_time:%Y-%m-%d %H:%M:%S%z}</span></div>"
|
||||||
f"<div id='run_end_time_cell'>End time: <span id='run_end_time'>{self.run_end_time:%Y-%m-%d %H:%M:%S%z}</span></div>"
|
f"<div id='run_end_time_cell'>End time: <span id='run_end_time'>{self.run_end_time:%Y-%m-%d %H:%M:%S%z}</span></div>"
|
||||||
@@ -5231,9 +5233,7 @@ class RotaBuilder(object):
|
|||||||
"</div>"
|
"</div>"
|
||||||
)
|
)
|
||||||
|
|
||||||
timetable.append(
|
heading_html = f"<h2>Rota start date: {self.start_date.isoformat()} ({self.weeks[-1]} weeks)</h2>"
|
||||||
f"<h2>Rota start date: {self.start_date.isoformat()} ({self.weeks[-1]} weeks)</h2>"
|
|
||||||
)
|
|
||||||
|
|
||||||
date_row = ["<th class='worker'></th>"]
|
date_row = ["<th class='worker'></th>"]
|
||||||
|
|
||||||
@@ -5249,15 +5249,18 @@ class RotaBuilder(object):
|
|||||||
f"<th title='{d}' class='{th_class}' data-date='{d}'>Week {week}: {day}</th>"
|
f"<th title='{d}' class='{th_class}' data-date='{d}'>Week {week}: {day}</th>"
|
||||||
)
|
)
|
||||||
n = n + 1
|
n = n + 1
|
||||||
timetable.append(f"<tr class='data-row'>{''.join(date_row)}</tr>")
|
# Header row (dates) should be placed in a proper thead
|
||||||
|
header_row_html = f"<thead><tr class='data-row'>{''.join(date_row)}</tr></thead>"
|
||||||
|
|
||||||
current_site = ""
|
current_site = ""
|
||||||
|
|
||||||
for worker in self.get_all_workers():
|
for worker in self.get_all_workers():
|
||||||
if worker.site != current_site:
|
if worker.site != current_site:
|
||||||
try:
|
try:
|
||||||
|
site = worker.site
|
||||||
|
site_count = len(self.workers_at_sites.get(site, []))
|
||||||
timetable.append(
|
timetable.append(
|
||||||
f"<tr><th class='site-title'>{worker.site} n={len(self.workers_at_sites[worker.site])} fte={self.full_time_equivalent_sites[worker.site]}</th><tr>"
|
f"<tr><th class='site-title'>{site} n={site_count}</th></tr>"
|
||||||
)
|
)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
print(e)
|
print(e)
|
||||||
@@ -5675,7 +5678,8 @@ class RotaBuilder(object):
|
|||||||
else:
|
else:
|
||||||
result_string = "Rota not run"
|
result_string = "Rota not run"
|
||||||
|
|
||||||
joined_timetable = "\n".join(timetable)
|
# Wrap the remaining rows in a tbody and prepend the thead
|
||||||
|
joined_timetable = header_row_html + "\n<tbody>\n" + "\n".join(timetable) + "\n</tbody>"
|
||||||
|
|
||||||
hard_constrain_shift_info = []
|
hard_constrain_shift_info = []
|
||||||
for worker in self.workers:
|
for worker in self.workers:
|
||||||
@@ -5781,6 +5785,8 @@ class RotaBuilder(object):
|
|||||||
html = f"""
|
html = f"""
|
||||||
<body>
|
<body>
|
||||||
<div class="table-div" id="{table_name}">
|
<div class="table-div" id="{table_name}">
|
||||||
|
{run_times_html}
|
||||||
|
{heading_html}
|
||||||
<table id="main-table">{joined_timetable}</table>
|
<table id="main-table">{joined_timetable}</table>
|
||||||
</div>
|
</div>
|
||||||
{warnings_html}
|
{warnings_html}
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ class Worker(BaseModel):
|
|||||||
|
|
||||||
shift_fte_overrides: dict[str, int] = {} # Need checks to ensure shifts exist
|
shift_fte_overrides: dict[str, int] = {} # Need checks to ensure shifts exist
|
||||||
|
|
||||||
weekend_shift_target_number: int = 0
|
weekend_shift_target_number: float = 0.0
|
||||||
avoid_shifts_on_dates: list[AvoidShiftOnDates] = []
|
avoid_shifts_on_dates: list[AvoidShiftOnDates] = []
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user