Bug: saveThrottles validated and saved throttles in same loop.
Invalid entry mid-loop stopped processing but left already-saved
throttles committed, and omitted throttles could still get deleted
via notToDelete tracking — partial/inconsistent state on failure.
- app/Controllers/Jobs.php: split into two passes — validate all
throttleData entries first; on any invalid entry, roll back
transaction and return failure immediately before touching DB.
Only save/delete once full payload validated. Drop now-redundant
$success flag folded into invalid-entry early return.
- tests/Controllers/JobsControllerTest.php: add test asserting
existing throttles stay unchanged in DB when payload contains
invalid throttle data.
Signed-off-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
Throttle POST field parsing used preg_replace with an unanchored
lazy pattern to pull numeric ids out of field names, which could
mis-extract or silently fall through on unexpected key formats.
- Replace preg_replace('/.*?_(\d+)$/', ...) with preg_match against
an anchored pattern ('/^throttle_count_(\d+)$/' and
'/^throttle_period_(\d+)$/') in app/Controllers/Jobs.php
- Only process the key when the anchored pattern actually matches,
avoiding bogus $throttleId values feeding $arraySave/$notToDelete
Signed-off-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
- JobThrottle::saveValue now returns int throttle_id instead of bool:
new inserts return the DB-generated insertID, updates return the
existing throttleId.
- Jobs controller collects saved ids into $notToDelete using the
returned value, so newly inserted throttles are correctly tracked.
Fixes bug where newly inserted throttles had no id captured,
causing them to be wrongly deleted in the post-save cleanup step.
Signed-off-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
Introduce a lightweight job scheduling system built on CI4 Tasks,
allowing due tasks to run via normal web traffic instead of relying
solely on external cron/Task Scheduler processes.
- Add JobRunner filter: runs TaskRunner after response send via
shutdown function, throttled per-minute via cache, respects
jobs_mode config ('auto'/'web'/'manual') and max-seconds budget
- Register jobrunner filter globally (app/Config/Filters.php),
disabled during testing to avoid heartbeat log spam
- Add Config/Tasks.php with jobs_heartbeat scheduled task (debug
log every minute) as scaffolding for future job commands
- Add Config/Jobs.php for mode/webMaxSeconds defaults
- Add Jobs controller + views (manage, settings_config,
utilities_config, partial/job_throttles) for configuring mode,
web max seconds, and per-period throttles; process-all/selected
actions stubbed for a later phase
- Add gulp task to copy jobs.svg menubar icon
- Fix tooltip clipping: use container: 'body' for bootstrap
tooltips and add max-width/text-align rules for tooltip-inner /
ui-tooltip in ospos.css
- Fix missing closing div in partial/footer.php layout
Signed-off-by: objecttothis <17935339+objecttothis@users.noreply.github.com>