Scope manual sync buttons to current view dates only
Sync rota and pull timesheets now operate on the 7-day view window rather than rolling default windows — reduces API calls and allows backdating. Cron job still uses rolling defaults via runRotaSync()/runTimesheetSync(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9bfd14a082
commit
ffefa1914f
9 changed files with 81 additions and 60 deletions
File diff suppressed because one or more lines are too long
2
frontend/dist/index.html
vendored
2
frontend/dist/index.html
vendored
|
|
@ -5,7 +5,7 @@
|
|||
<meta name="viewport" content="width=1280" />
|
||||
<meta name="theme-color" content="#2d6a4f" />
|
||||
<title>HK Planner</title>
|
||||
<script type="module" crossorigin src="/hk-planner/assets/index-C9TVzZ7i.js"></script>
|
||||
<script type="module" crossorigin src="/hk-planner/assets/index-Bp4tnr99.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/hk-planner/assets/index-B7_UXJgZ.css">
|
||||
<link rel="manifest" href="/hk-planner/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/hk-planner/registerSW.js"></script></head>
|
||||
<body>
|
||||
|
|
|
|||
2
frontend/dist/sw.js
vendored
2
frontend/dist/sw.js
vendored
|
|
@ -1 +1 @@
|
|||
if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(i[o])return;let t={};const c=e=>n(e,o),d={module:{uri:o},exports:t,require:c};i[o]=Promise.all(s.map(e=>d[e]||c(e))).then(e=>(r(...e),t))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"a2c395d8c225f1b3ea12388f15189bce"},{url:"index.html",revision:"3b1c49874f107c5a3d6697cd6a89320e"},{url:"icons/icon-512.png",revision:"c32202b9deed67ef38331f63dec9d1c8"},{url:"icons/icon-192.png",revision:"46ece317d50d10b8f5e225e073b3221d"},{url:"assets/index-C9TVzZ7i.js",revision:null},{url:"assets/index-B7_UXJgZ.css",revision:null},{url:"manifest.webmanifest",revision:"c2510de876adb84db0c4b300b71216fa"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/hk-planner/index.html"),{denylist:[/\/api\//]}))});
|
||||
if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,r)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(i[t])return;let o={};const c=e=>n(e,t),d={module:{uri:t},exports:o,require:c};i[t]=Promise.all(s.map(e=>d[e]||c(e))).then(e=>(r(...e),o))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"a2c395d8c225f1b3ea12388f15189bce"},{url:"index.html",revision:"455924148ee524d7363268ccabc71ea8"},{url:"icons/icon-512.png",revision:"c32202b9deed67ef38331f63dec9d1c8"},{url:"icons/icon-192.png",revision:"46ece317d50d10b8f5e225e073b3221d"},{url:"assets/index-Bp4tnr99.js",revision:null},{url:"assets/index-B7_UXJgZ.css",revision:null},{url:"manifest.webmanifest",revision:"c2510de876adb84db0c4b300b71216fa"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/hk-planner/index.html"),{denylist:[/\/api\//]}))});
|
||||
|
|
|
|||
|
|
@ -83,11 +83,11 @@ export function putWorkforceDepartments(dept_ids) {
|
|||
body: JSON.stringify({ dept_ids }),
|
||||
});
|
||||
}
|
||||
export function syncWorkforce() {
|
||||
return request('/workforce/sync', { method: 'POST' });
|
||||
export function syncWorkforce(start, end) {
|
||||
return request(`/workforce/sync?start=${start}&end=${end}`, { method: 'POST' });
|
||||
}
|
||||
export function syncTimesheets() {
|
||||
return request('/workforce/sync-timesheets', { method: 'POST' });
|
||||
export function syncTimesheets(start, end) {
|
||||
return request(`/workforce/sync-timesheets?start=${start}&end=${end}`, { method: 'POST' });
|
||||
}
|
||||
export function getWorkforceShifts(start, end) {
|
||||
return request(`/workforce/shifts?start=${start}&end=${end}`);
|
||||
|
|
|
|||
|
|
@ -116,12 +116,12 @@ export function putWorkforceDepartments(dept_ids: string[]): Promise<{ ok: boole
|
|||
})
|
||||
}
|
||||
|
||||
export function syncWorkforce(): Promise<{ ok: boolean; from: string; to: string; dates_synced: number }> {
|
||||
return request('/workforce/sync', { method: 'POST' })
|
||||
export function syncWorkforce(start: string, end: string): Promise<{ ok: boolean; from: string; to: string; dates_synced: number }> {
|
||||
return request(`/workforce/sync?start=${start}&end=${end}`, { method: 'POST' })
|
||||
}
|
||||
|
||||
export function syncTimesheets(): Promise<{ ok: boolean; from: string; to: string; dates_synced: number }> {
|
||||
return request('/workforce/sync-timesheets', { method: 'POST' })
|
||||
export function syncTimesheets(start: string, end: string): Promise<{ ok: boolean; from: string; to: string; dates_synced: number }> {
|
||||
return request(`/workforce/sync-timesheets?start=${start}&end=${end}`, { method: 'POST' })
|
||||
}
|
||||
|
||||
export function getWorkforceShifts(start: string, end: string): Promise<Record<string, WfDayData>> {
|
||||
|
|
|
|||
|
|
@ -250,13 +250,15 @@ export function Planner() {
|
|||
}
|
||||
// ── Workforce sync ───────────────────────────────────────────────────────────
|
||||
async function syncRota() {
|
||||
if (!bookings)
|
||||
return;
|
||||
const start = bookings.dates[0];
|
||||
const end = bookings.dates[bookings.dates.length - 1];
|
||||
setSyncing(true);
|
||||
try {
|
||||
await syncWorkforce();
|
||||
if (bookings) {
|
||||
const shifts = await getWorkforceShifts(bookings.dates[0], bookings.dates[bookings.dates.length - 1]);
|
||||
setWfShifts(shifts);
|
||||
}
|
||||
await syncWorkforce(start, end);
|
||||
const shifts = await getWorkforceShifts(start, end);
|
||||
setWfShifts(shifts);
|
||||
flash('Rota synced from Workforce');
|
||||
}
|
||||
catch (e) {
|
||||
|
|
@ -267,13 +269,15 @@ export function Planner() {
|
|||
}
|
||||
}
|
||||
async function syncTimesheetData() {
|
||||
if (!bookings)
|
||||
return;
|
||||
const start = bookings.dates[0];
|
||||
const end = bookings.dates[bookings.dates.length - 1];
|
||||
setTimesheetSyncing(true);
|
||||
try {
|
||||
await syncTimesheets();
|
||||
if (bookings) {
|
||||
const shifts = await getWorkforceShifts(bookings.dates[0], bookings.dates[bookings.dates.length - 1]);
|
||||
setWfShifts(shifts);
|
||||
}
|
||||
await syncTimesheets(start, end);
|
||||
const shifts = await getWorkforceShifts(start, end);
|
||||
setWfShifts(shifts);
|
||||
flash('Timesheets pulled from Workforce');
|
||||
}
|
||||
catch (e) {
|
||||
|
|
|
|||
|
|
@ -298,13 +298,14 @@ export function Planner() {
|
|||
// ── Workforce sync ───────────────────────────────────────────────────────────
|
||||
|
||||
async function syncRota() {
|
||||
if (!bookings) return
|
||||
const start = bookings.dates[0]
|
||||
const end = bookings.dates[bookings.dates.length - 1]
|
||||
setSyncing(true)
|
||||
try {
|
||||
await syncWorkforce()
|
||||
if (bookings) {
|
||||
const shifts = await getWorkforceShifts(bookings.dates[0], bookings.dates[bookings.dates.length - 1])
|
||||
setWfShifts(shifts)
|
||||
}
|
||||
await syncWorkforce(start, end)
|
||||
const shifts = await getWorkforceShifts(start, end)
|
||||
setWfShifts(shifts)
|
||||
flash('Rota synced from Workforce')
|
||||
} catch (e) {
|
||||
flash(e instanceof Error ? e.message : 'Sync failed', true)
|
||||
|
|
@ -314,13 +315,14 @@ export function Planner() {
|
|||
}
|
||||
|
||||
async function syncTimesheetData() {
|
||||
if (!bookings) return
|
||||
const start = bookings.dates[0]
|
||||
const end = bookings.dates[bookings.dates.length - 1]
|
||||
setTimesheetSyncing(true)
|
||||
try {
|
||||
await syncTimesheets()
|
||||
if (bookings) {
|
||||
const shifts = await getWorkforceShifts(bookings.dates[0], bookings.dates[bookings.dates.length - 1])
|
||||
setWfShifts(shifts)
|
||||
}
|
||||
await syncTimesheets(start, end)
|
||||
const shifts = await getWorkforceShifts(start, end)
|
||||
setWfShifts(shifts)
|
||||
flash('Timesheets pulled from Workforce')
|
||||
} catch (e) {
|
||||
flash(e instanceof Error ? e.message : 'Timesheet sync failed', true)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue