hr_lite 0.21.2 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +75 -0
- data/README.md +54 -2
- data/app/assets/javascripts/hr_lite/confirm.js +18 -3
- data/app/assets/javascripts/hr_lite/geo_punch.js +1 -1
- data/app/assets/javascripts/hr_lite/nav.js +17 -0
- data/app/assets/javascripts/hr_lite/select_filter.js +46 -0
- data/app/assets/stylesheets/hr_lite/hr_lite.css +223 -83
- data/app/controllers/hr_lite/admin/assets_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/attendances_controller.rb +31 -0
- data/app/controllers/hr_lite/approvals_controller.rb +1 -12
- data/app/controllers/hr_lite/attendance_controller.rb +7 -0
- data/app/controllers/hr_lite/holidays_controller.rb +1 -0
- data/app/controllers/hr_lite/home_controller.rb +40 -3
- data/app/controllers/hr_lite/hr_requests_controller.rb +1 -1
- data/app/controllers/hr_lite/leave_requests_controller.rb +13 -2
- data/app/controllers/hr_lite/regularization_requests_controller.rb +10 -2
- data/app/controllers/hr_lite/tax_declarations_controller.rb +4 -0
- data/app/helpers/hr_lite/application_helper.rb +43 -30
- data/app/jobs/hr_lite/attendance_close_job.rb +6 -1
- data/app/models/hr_lite/approval.rb +5 -0
- data/app/models/hr_lite/attendance_record.rb +26 -0
- data/app/models/hr_lite/employee_profile.rb +1 -0
- data/app/models/hr_lite/hr_request.rb +2 -1
- data/app/models/hr_lite/office_location.rb +12 -0
- data/app/models/hr_lite/regularization_request.rb +10 -4
- data/app/services/hr_lite/attendance_puncher.rb +8 -3
- data/app/views/hr_lite/admin/assets/index.html.erb +3 -2
- data/app/views/hr_lite/admin/assets/new.html.erb +6 -2
- data/app/views/hr_lite/admin/attendances/index.html.erb +37 -6
- data/app/views/hr_lite/admin/attendances/show.html.erb +11 -7
- data/app/views/hr_lite/admin/attendances/week.html.erb +42 -0
- data/app/views/hr_lite/admin/checklists/index.html.erb +1 -1
- data/app/views/hr_lite/admin/comp_off_requests/index.html.erb +2 -2
- data/app/views/hr_lite/admin/comp_off_requests/show.html.erb +2 -2
- data/app/views/hr_lite/admin/documents/index.html.erb +1 -1
- data/app/views/hr_lite/admin/employees/_form.html.erb +15 -7
- data/app/views/hr_lite/admin/employees/show.html.erb +5 -5
- data/app/views/hr_lite/admin/expenses/index.html.erb +2 -2
- data/app/views/hr_lite/admin/leave_balances/index.html.erb +3 -3
- data/app/views/hr_lite/admin/leave_requests/index.html.erb +2 -2
- data/app/views/hr_lite/admin/leave_requests/show.html.erb +4 -6
- data/app/views/hr_lite/admin/loans/new.html.erb +2 -1
- data/app/views/hr_lite/admin/overview/index.html.erb +3 -3
- data/app/views/hr_lite/admin/regularization_requests/index.html.erb +1 -1
- data/app/views/hr_lite/admin/shared/_approvals_tabs.html.erb +6 -5
- data/app/views/hr_lite/appraisals/show.html.erb +3 -3
- data/app/views/hr_lite/approvals/index.html.erb +1 -1
- data/app/views/hr_lite/attendance/_month_grid.html.erb +21 -26
- data/app/views/hr_lite/attendance/_punch_card.html.erb +29 -7
- data/app/views/hr_lite/attendance/show.html.erb +36 -7
- data/app/views/hr_lite/benefits/index.html.erb +1 -1
- data/app/views/hr_lite/calendar/show.html.erb +29 -22
- data/app/views/hr_lite/comp_off_requests/index.html.erb +3 -3
- data/app/views/hr_lite/comp_off_requests/new.html.erb +3 -2
- data/app/views/hr_lite/documents/index.html.erb +32 -30
- data/app/views/hr_lite/employee_profiles/show.html.erb +2 -2
- data/app/views/hr_lite/expenses/index.html.erb +17 -35
- data/app/views/hr_lite/expenses/new.html.erb +11 -6
- data/app/views/hr_lite/holidays/_next_holiday.html.erb +11 -8
- data/app/views/hr_lite/holidays/index.html.erb +6 -6
- data/app/views/hr_lite/home/index.html.erb +29 -19
- data/app/views/hr_lite/hr_requests/index.html.erb +7 -24
- data/app/views/hr_lite/hr_requests/new.html.erb +7 -5
- data/app/views/hr_lite/hr_requests/show.html.erb +4 -0
- data/app/views/hr_lite/kudos/index.html.erb +4 -3
- data/app/views/hr_lite/leave_balances/index.html.erb +14 -5
- data/app/views/hr_lite/leave_requests/_balance_chips.html.erb +5 -3
- data/app/views/hr_lite/leave_requests/_out_list.html.erb +16 -0
- data/app/views/hr_lite/leave_requests/index.html.erb +8 -21
- data/app/views/hr_lite/leave_requests/new.html.erb +22 -9
- data/app/views/hr_lite/leave_requests/show.html.erb +3 -5
- data/app/views/hr_lite/loans/index.html.erb +18 -20
- data/app/views/hr_lite/policies/index.html.erb +1 -1
- data/app/views/hr_lite/regularization_requests/index.html.erb +2 -2
- data/app/views/hr_lite/regularization_requests/new.html.erb +11 -8
- data/app/views/hr_lite/resignations/show.html.erb +1 -1
- data/app/views/hr_lite/salary_slips/_slip_detail.html.erb +9 -3
- data/app/views/hr_lite/salary_slips/index.html.erb +48 -44
- data/app/views/hr_lite/shared/_bell.html.erb +1 -1
- data/app/views/hr_lite/shared/_form_errors.html.erb +1 -1
- data/app/views/hr_lite/tax_declarations/show.html.erb +24 -19
- data/app/views/hr_lite/team/show.html.erb +2 -2
- data/app/views/layouts/hr_lite/application.html.erb +24 -8
- data/config/routes.rb +3 -1
- data/lib/hr_lite/configuration.rb +16 -2
- data/lib/hr_lite/notifications.rb +1 -0
- data/lib/hr_lite/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c6db8fc763b744461b7e4d52e484bc3a74a82fe95f9d35b51025d4eedb453e6c
|
|
4
|
+
data.tar.gz: 44a8caeed2447b02ffcf465befb0e965f101a79e5bb6d721cf138d53a1063f63
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6190cb5ca0db661d5aeb3e3c1bd6d359c1a10c6a798c7f99e67b20f27e9890fe6caa130fbf08fb6c5b1727b7aadde38ccff63285a41d9a403555d6befdc821eb
|
|
7
|
+
data.tar.gz: 39faf582aebd8d31c427da5bc1aeb118e1e750ef12a731ef6336be72b1c58f40a45a4b443843371058fa2a2f04a50f176198237fcbd122234fa45e734088eeca
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,81 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.22.0] - 2026-10-09
|
|
11
|
+
|
|
12
|
+
The HRMS UI/UX pass: Keka/greytHR patterns and a ui-ux-pro-max review of every screen, phone first. No migrations. Hosts that theme through `--hrl-*` variables keep their values; the engine defaults for radius, info background and muted text change (see Changed).
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Work hours (`config.work_hours = { day: 8, probation_day: 9, week: 40 }`, off by default): the nightly close job marks a Mon–Fri day with a check-out but fewer worked hours than required (9 on probation) as a half day and tells the employee ("You worked 7.0 of 8h on 06 Jul — marked half day"). A regularization ticket with no times and a reason fixes it back to present: self-fixed within the `self_regularization` window and weekly cap, otherwise sent to HR. Home's "Needs a fix" list shows such days as "Short day". New admin screen Team attendance → Weekly hours (`/admin/attendances/week?date=`): each person's Mon–Fri hours, average per worked day, target (`week` less a fifth per holiday or full-day leave; the current week counts only the days already over) and a "Below target" badge. Saturdays are never counted.
|
|
16
|
+
- Punch locations on Team attendance: a Location column names where each side was punched (the office whose radius covers it, else "Off-site · 2.0 km from HQ", or "No GPS") and how far apart check-in and check-out were, with a warning badge over 500 m (`AttendanceRecord::PUNCH_GAP_ALERT_M`). A "Where people punched" card counts people per check-in and per check-out place. New `OfficeLocation.place` and `AttendanceRecord#punch_gap_m`.
|
|
17
|
+
- `config.require_punch_location = true` refuses a punch with no GPS fix instead of recording and flagging it.
|
|
18
|
+
- Theming: new `--hrl-*` variables for the type ramp, line heights, spacing, large and pill radii, extra shadows, focus ring, motion, z-index, tap targets, and the colour roles `--hrl-ink-2`, `--hrl-field` and `--hrl-scrim`. The README lists every variable with its role.
|
|
19
|
+
- Keyboard: every focused control shows a 2px accent ring (kudos badge chips included), focus scrolls clear of the app bar and tab bar, and a "Skip to content" link is the first Tab stop so desktop users skip the side rail. Reduced-motion users get no transitions or animations. New `.hrl-sr-only` utility.
|
|
20
|
+
- Leave-type badge `.hrl-badge--type`: ink text on grey with an 8px dot in the HR-chosen colour, set inline as `--hrl-type`.
|
|
21
|
+
- Navigation: the current screen's link carries `aria-current="page"`, and the phone "More" tab lights up in the accent colour, and carries `aria-current="true"` so screen readers hear it too, when the current screen lives in the sheet or under admin. New helper `hrl_nav_active?(item)`.
|
|
22
|
+
- Sub-screens show a 44px "‹ Leaves", "‹ Attendance" or "‹ Calendar" link to their parent tab above the title: balances, comp-off, regularization, holidays, and the leave form and request. A view names its tab with `content_for(:back, "Leaves")`; new `.hrl-backlink`. The leave request's "Back" button gives way to it.
|
|
23
|
+
- Attendance day detail: tap any day up to today on My attendance to open a card below the grid (`?day=YYYY-MM-DD#day`) with the day's status (a badge in the cell's colour), check-in, check-out, worked time, half-day part, leave type, holiday name, flag reason and latest regularization ticket. "Fix this day" opens the ticket form with that date filled in, unless the day is a holiday, weekly off or full-day leave, or already has a pending ticket. The whole cell is the link, here and on an employee's admin month (was the digit alone, 8x17px), and day numbers keep the cell's ink. On the admin month a tapped day scrolls to its fix form (`#regularize`), and upcoming days are no longer links. Below 481px the grid alone reaches 4px from the card edge (the card's text keeps its padding) and the cell gap drops to 2px, so cells are 44px wide at 360px.
|
|
24
|
+
- Apply for leave: a card under the form, "Out in the next 2 weeks", names colleagues with approved leave from today to 14 days out and their dates, never the leave type (up to 10, then "+N more"). Home's "On leave this week" list and this card share the new `leave_requests/_out_list` partial.
|
|
25
|
+
- Home Today card: under the punch button, the card lists the last 7 days that are absent, missing a check-out or flagged ("Mon 5 Jul · Absent"), each with a 44px "Fix" (screen readers hear "Fix Mon 5 Jul") that opens the ticket form for that date. Days with a pending ticket, holidays, weekly offs, full-day leave and days before joining are left out, and so is a shift from yesterday with no check-out yet (a night shift can still be running). Under it, quick actions: Apply leave, Fix a punch, Comp-off and Payslip. The punch card takes an optional `attention:` local; My attendance passes none and shows neither.
|
|
26
|
+
- Attendance month grid: a day with a pending regularization ticket on My attendance gets a dashed `--hrl-ink-2` border (`.hrl-mgrid__day--pending`), screen readers hear ", fix pending", and the legend keys it as "Fix pending". The partial takes an optional `pending_dates:` set; an employee's admin month passes none and shows no key.
|
|
27
|
+
- Home "My requests": your 5 newest pending leave requests, attendance fixes and comp-off requests, each a 44px row with its dates and a Pending badge that opens the leave request, the ticket list or the comp-off list. The card is left out when nothing is pending.
|
|
28
|
+
- Home "Waiting on you": anyone with pending approvals, their own or ones they are covering for a delegator, sees "3 requests waiting on you" with a primary "Review requests" button to the inbox, above the Today card. Approvers with no routed flow (a manager or HR deciding leave, comp-off and attendance fixes off the HR queues) see the same card for the requests they may decide, never their own, and its button opens Leave approvals. Nobody else sees the card. New scope `Approval.pending_for(user)`, which the inbox now uses too. Deviation: the card sits above the Home grid, not inside it, so at 1024px and up it spans both columns instead of stretching to the Today card's height.
|
|
29
|
+
- Type-to-filter staff pickers: the existing-staff and "Reports to" selects on the employee form, the loan's Employee and the asset hand-over get a 44px filter box above them (new `select_filter.js`, `.hrl-filter`), labelled for its field ("Filter existing staff", "Filter Reports to", else "Type a name to filter"). Typing "mee" leaves only Meera and picks her; Escape or an emptied box puts back the stored pick, a filter that matches nobody leaves the list as it was (so the field still submits), and Enter never submits the form. The "Existing staff member" label now names its select (a hidden field took its id). The select keeps its name and still submits; without JavaScript it is a plain select. Mark any select with `data-hrl-filter="<label>"` to get one. Deviation: Record leave keeps its type-ahead employee box (a datalist), since it has no select to filter.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- Engine defaults: `--hrl-radius` 14px to 16px, `--hrl-radius-sm` 9px to 12px, `--hrl-info-bg` #dbeafe to #eff6ff (accent text on it now 4.75:1) and `--hrl-muted` #6b7280 to #4b5563 (4.5:1 or better on the page background). Hosts that set these variables see no change.
|
|
33
|
+
- Type: every screen except the ID card uses the six-step ramp (12/14/16/18/20/24px) and weights 400/600/700. Nothing renders below 12px, and the page title grows from 20px to 24px at 768px.
|
|
34
|
+
- Radii: every corner outside the ID card is 12, 16 or 20px or a pill. Month-grid day cells go from 7px to `--hrl-radius-sm`, pills use `--hrl-radius-pill`, and the phone "More" sheet gets 20px top corners (`--hrl-radius-lg`).
|
|
35
|
+
- Long text: badges clip at their container's width, buttons wrap long labels, and definition-list values shrink instead of widening the page, so 60-character names no longer cause sideways scroll. Muted badges use `--hrl-ink-2`.
|
|
36
|
+
- Forms: inputs are 16px with a `--hrl-field` border (3:1 or better), an invalid field turns its border and label red, hints are styled everywhere, kudos chips and check-row labels are 44px tall with an 8px gap, and the error box is announced and takes focus. Mandatory fields carry `required`, so the browser stops an empty submit. `.hrl-card--warn` (expiring documents) now has its amber fill.
|
|
37
|
+
- Phone tab bar: tabs sit 8px apart (`--hrl-gap-target`) and size to their labels, each at least 44px wide, so "Attendance" fits at 320px without tabs touching.
|
|
38
|
+
- Side rail (768px and up): every link, the brand and the back-to-CMS link are at least 44px tall (links were 38px).
|
|
39
|
+
- Phone app bar: the brand and your name are 44px targets that end in an ellipsis instead of wrapping (the brand never narrower than 44px), your name opens My profile, and the bar stays 61px tall with the notifications link and a 60-character name (was up to 92px). The unread count reads "3 unread" to screen readers.
|
|
40
|
+
- Navigation groups: the rail and the phone "More" sheet group your screens under My work, Time, Money, Me and Company (`group:` on `NAV_ITEMS`, which is reordered to keep each group together). Below 481px the sheet shows two columns, so an employee's sheet fits without scrolling (520px, was 661px in a 444px box). It can grow to just below the app bar instead of stopping at 60vh. A scrim dims the page behind it; Escape or a tap on the scrim closes it, and Escape returns focus to More. When `config.back_link` is set, it is the sheet's first row.
|
|
41
|
+
- Layout: two-column card grids start at 1024px (was 700px, which clipped the slip's Earnings card at 768px) without a doubled gap below them. Stacked tables also stack between 768 and 1023px beside the side rail. Stacked action cells sit right-aligned with no empty label, the last row loses its 6px band, and side-by-side actions in table mode sit 8px apart. Amount, Net pay, Cover and Dependants headers right-align over their values. New `.hrl-card__link` (44px text link) and `.hrl-row--mb` replace inline margin styles.
|
|
42
|
+
- Page actions: below 481px a screen's action buttons (Apply, New claim, Balances...) sit on their own full-width row under the title, starting at the screen edge and sharing the row, so they are easy to reach with a thumb. Icon-only arrows (the Team day pager) keep their own width. From 481px they stay right-aligned beside the title as before. The appraisal and leave-decision "Back" buttons become "‹ Appraisals" and "‹ Approvals" back links.
|
|
43
|
+
- Attendance month grid: every day except an upcoming working day shows its state as a code (P, ½, L, ½L, H, WO, A) as well as a colour, and screen readers hear it in words ("16 Oct, Leave", plus "worked" on a punched holiday or weekly off, and "Flagged"). The legend keys every code, Today, Flagged and Upcoming. A half-day leave gets its own half-tinted cell instead of full leave's. Upcoming day numbers use `--hrl-muted` at full strength instead of 45% opacity. The invalid `role="grid"`/`"gridcell"` give way to labelled groups. Check-in and check-out times leave the cells for the day detail.
|
|
44
|
+
- Month navigation: on My attendance, the company calendar and an employee's admin month, the bare arrows become "‹ Sep" and "Nov ›" buttons that screen readers hear as "Previous month, September 2026" and "Next month, November 2026". The "Present · Half · Absent" line becomes wrapping badges, P, ½, L (new: leave days) and A, each read as "Present 4 days" and so on.
|
|
45
|
+
- Regularization form: one date and two time-only fields (were two date-and-time pickers), with the "leave blank" notes as hints under them. A check-out earlier than the check-in is saved on the next morning for a night shift; a ticket's check-out may fall on the next day only before the check-in's time.
|
|
46
|
+
- Company calendar: cells show a short code, "H" for a holiday or "2 off" for leaves, instead of clipped names and leave-type codes, and today gets the accent ring. The legend keys "H Holiday", "N off On leave", "Weekly off" and "Today". Under the legend, a list names every holiday ("Fri 2 Oct: Gandhi Jayanti (holiday)") and colleague on leave ("Fri 16 Oct: Meera, on leave"; a range reads "Tue 29 Jun – Fri 2 Jul") that month, all in one date style. Colleagues show by name only, with no leave type, as on Home. "Holiday list" moves to the page actions, and from 768px cells are 88px tall.
|
|
47
|
+
- Today card: while checked in, the badge reads "In since 09:30 · 3h 15m so far" (worked time as of the page load, no timer), the location status under the punch button is a polite live region (`role="status"`) that is never `hidden`, so its first message is announced, and "View my month" is a 44px `.hrl-card__link`.
|
|
48
|
+
- Apply for leave: Type is a row of 44px chips that show what is left ("Casual · 9 left", a trailing " leave" dropped from the name, and "Leave without pay · Unpaid"), with the loss-of-pay note as a hint under them, and Day is a chip row with Full day checked. From starts empty, and a blank To means one day ("To (leave blank for one day)"). `?leave_type_id=` and `?date=YYYY-MM-DD` pre-check the type and fill From. The form drops the balance card above it, since the chips show what is left, and the balance card drops its Apply button on My leaves (it stays on Home). New helper `hrl_days` prints day counts without ".0". Deviation: at 360x740 Submit still ends at 921px, below the 687px tab bar (937px before), so it takes one short scroll; From is on the first screen. Five leave types need four chip rows, and the loss-of-pay hint and the 90px reason box stay, so the target "Submit in view" cannot be met without the sticky action bar that was ruled out.
|
|
49
|
+
- Leave badges: the balance card reads "Casual leave · 9 of 10 left" (was "CL 9.0/10.0") and it and My leaves' type badges are `.hrl-badge--type`, ink on grey at 16:1 (was the type's colour on its tint, 1.96 to 3.65:1). Day counts drop the ".0" on My leaves, a leave request, Balances, Comp-off, the "N day(s) are beyond your balance" notice, and HR's leave requests, leave balances, comp-off requests and overview; `hrl_days(nil)` shows an em dash.
|
|
50
|
+
- My leaves: each request is one tappable row (new `.hrl-listrow`), the type badge and name with the status badge at the end, then "16 Oct · 1 day", about 71px tall at 360px (was a stacked table of about 190px with a small "View" link). A leave request's status badge is coloured like the list's (`hrl_request_status_badge`), so Rejected reads red.
|
|
51
|
+
- Leave balances: a primary "Apply" in the page actions, and each card ends in a 44px "Apply" link that opens the form with its type pre-checked. The comp-off card reads "Credited" instead of "Entitled". With no paid type set up, the page shows "No leave types set up yet. Ask HR." instead of a bare title. `.hrl-card__link` is now at least 44px wide as well as tall.
|
|
52
|
+
- Home: "Out today" becomes "On leave this week", listing approved leave that overlaps the current Mon–Sun week, and when the list is empty it reads "Nobody is on leave this week." instead of "Everyone's in today.", which claimed attendance it never checked. "Team board" is a 44px `.hrl-card__link`.
|
|
53
|
+
- Home: "Next holiday" becomes "Upcoming holidays", listing up to 3 company-wide holidays in the next 60 days ("Fri 2 Oct · Gandhi Jayanti · in 14 days"); optional holidays stay off it. With none due it reads "No holidays in the next 2 months." (was "No upcoming holidays on the calendar."), and its link is a 44px "All holidays" to the holiday list (was "Company calendar").
|
|
54
|
+
- Salary slips: the slips list comes first under a "Slips" heading, so the latest View and PDF sit in the first phone screen (were at 899px, behind the tab bar). The salary structure table and TDS note fold into a closed "Show salary structure" disclosure under "My salary", so no structure amounts show until it is opened. Deviation: upcoming and earlier revisions stay visible below it.
|
|
55
|
+
- Salary slip (employee and admin views): four tiles open the slip, Net pay, Gross, Deductions and "Payable / LOP days", so Net pay sits at about 172px on a 360px phone (was about 618px, below the fold). Tiles are 2x2 up to 1099px and 4 across from 1100px. The amount in words moves to its own muted 14px line under Net pay, and the Days line below reads "30 payable / 1 LOP of 31" like the tile (was "30.0 payable / 1.0 LOP"). Deviation: new `.hrl-kpis--money` sets the tile amounts at 18px below 481px (24px above), so "₹1,01,612.91" fits a half-width tile at 320px instead of splitting its digits.
|
|
56
|
+
- Loans: each loan's Monthly instalment, Repaid so far, Outstanding and Next deduction are a definition list with real text labels at every width (were a stacked table whose labels existed only as CSS `::before` text), and "Already deducted" keeps its Month and Amount headers on phones. With no loans, a 44px "Ask HR about an advance" link opens Ask HR with Payroll query chosen; `?category=` pre-selects any help-desk category.
|
|
57
|
+
- My documents: "On file" comes first (its heading at 134px on a 360px phone, was 675px behind the tab bar), and the upload form folds into an "Upload a document" disclosure under it, open when nothing is on file or the upload failed. Category is a row of 44px chips with none chosen and a choice required (Aadhaar was preselected, so any upload could be filed as an Aadhaar); the chip and the list say "PAN", not "Pan". The file picker offers PDFs and images only, and "Open" is a 44px button (was a 14px link) with Remove beside it at every width (in table mode Remove used to drop under it with no gap).
|
|
58
|
+
- Ask HR: "What is this about" is a row of 44px chips, one per category and labelled as in the request list ("ID card", not "Id card"), with none chosen and a choice required (was a 12-option select), so one tap picks it. `?category=` still pre-checks one. Deviation: at 360x740 "Send to HR" ends at 820px, below the 687px tab bar (531px before), so it takes one short scroll.
|
|
59
|
+
- Tax declaration: Tax regime is two 44px radio rows, "New regime" and "Old regime", each with a hint line under it (was a select whose option text was clipped at 360px). Under the new regime the claims fold into a closed "Deductions (old regime only)" disclosure, so Save draft is on the first phone screen; under the old regime it is open. Each "What it is (optional)" box has a visible muted label in place of its placeholder, 14px below its amount (was touching it). Save draft and Submit to HR share one action row under the claims, with Submit to HR the only primary button (Save draft is primary until there is something to submit). Submit to HR saves what is on screen and then submits it (it used to submit the last saved draft and drop unsaved edits). A failed save reopens the claims under the new regime too, so the red field shows. The form still posts `tax_declaration[regime]`.
|
|
60
|
+
- New claim: each category option says up front whether it needs a receipt and what is left of its cap this month, "Client entertainment (receipt needed, ₹5,000.00 left this month)", from the same figures as the Expenses screen; a category with no cap and no receipt rule shows its name alone. The receipt hint reads "Needed when the category says "receipt needed"." (was "the form will say so if yours does", which it did only after a failed submit). Deviation: at 360px the closed select clips a long label once chosen; the full text shows in the option list before choosing.
|
|
61
|
+
- Kudos wall: the composer folds into a full-width "Give kudos" button that opens it (open again after a failed post, with the error), so the first kudo sits at about 278px on a 360px phone (was about 540px).
|
|
62
|
+
- Holidays and Team board: past holidays are muted, and the next company-wide holiday (the one Home leads with, never an optional day) carries a "Next" badge beside its name. "Optional" sits beside the name too, so the blank-headed badge column and its empty cells are gone at every width. On the Team board today's "Not in yet" is a grey badge (was red, before anyone could be late); a past day with no punch stays a red "Absent". The stacked hours label reads "Hours today" or "Hours that day" like its column header, and "Raise a regularization ticket" is a 44px `.hrl-card__link`.
|
|
63
|
+
- Row actions: a policy's title on Policies and "Open" on Waiting on you are 44px buttons (were text links about 20px tall), and My HR profile's "Org chart" is its own 44px button under the details (was "· Org chart" inline after Reports to). A badge in a stacked table cell no longer stretches to the height of a button beside it, and in table mode a row with a 44px button centres its other cells on it, so a policy's version, date and acknowledgement line up with its title (they sat 12px higher).
|
|
64
|
+
- Expenses and Ask HR: claims and requests are `.hrl-listrow` rows instead of stacked tables (were about 263px and 255px tall at 360px). A claim reads its description and amount, then date, category and status (plus the payroll month or HR's note), with Withdraw at the right of the second line: 96px at 768px and up, 116px at 360px when the description wraps. An Ask HR request is one tappable row, subject and status, then category and date (89px at 360px when the subject wraps, 70px at 768px and up), and its Withdraw moves onto the request's page. `.hrl-listrow` wraps long unbroken text, and its title line (first child) uses the tight line height, so a two-line title is 40px. Deviations: a claim row is not a link, since a claim has no page of its own and Withdraw cannot sit inside a link; claims carry no "Receipt needed" badge, since a claim in a receipt-required category cannot be saved without one.
|
|
65
|
+
- HR admin tables: Team leave balances and an employee's Salary structures stack into labelled rows on phones and beside the side rail (768 to 1023px), like the engine's other tables, so neither scrolls sideways at 360px (they hid 20px and up to 33px). Each balance is labelled with its leave type's code ("CL 10 left, 0/10 used"), and a salary structure's Edit is a 44px button (was a 24x21px link). From 1024px both stay tables.
|
|
66
|
+
- HR admin forms: an employee's Blood group is a row of 44px chips, "Not set" and the eight groups, with the stored group checked (was a 9-option select); "Not set" saves no blood group (the blank option used to save an empty string). Add asset's Category is a row of 44px chips with none chosen and a choice required (was a select with "Other" preselected from the column default). Chips are at least 44px wide, so "A-" and "B-" no longer fall 1px short. The read-only Employee code on the edit form is now named by its label (the label pointed at no field).
|
|
67
|
+
- HR approvals tabs (Leaves, Comp-off, Regularization, Balances): the current tab carries `aria-current="page"`, so screen readers hear which one is open, not only see it in the accent colour. The tabs take 8px side padding (new `.hrl-row--tabs`), so all four sit in one row from 768px beside the side rail (469px of 485px with both pending counts showing; they needed 533px and wrapped). Below 481px they wrap with 9.6px gaps.
|
|
68
|
+
- HR overview: the Pending approvals card's "All requests" link is a 44px `.hrl-card__link` (was 73x16px small text). The KPI tiles are unchanged.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
- Attendance: a flagged punch's reason shows as text on the Today card ("Flagged: Check-in 2.4 km from Head office") instead of a hover-only tooltip that phones and screen readers never reached. The month grid's flag dot is hidden from screen readers; the day's label already says "Flagged".
|
|
72
|
+
- Team attendance: the day arrows are heard as "Previous day, Wednesday 7 October" and "Next day, …", a flagged row prints its reason beside the badge instead of in a tooltip, and "Edit / half day" is a 44px link (was 86x16) that opens the employee's month at the fix form.
|
|
73
|
+
- Attendance month grid: today with no punch yet shows "Today" with an accent ring instead of a red "A", and the Absent count on My attendance and an employee's admin month leaves it out. Every today cell gets the ring. Only the views change: `DayStatus` and `AttendanceSummary`, and so payroll, still count an unpunched today as absent.
|
|
74
|
+
- A double tap on a submit button sends one request: the button locks (dimmed, `aria-busy`) once the form submits, stays live when a confirm prompt is cancelled, and unlocks when Back restores the page. Punch forms keep their own location flow.
|
|
75
|
+
- Tax declaration: reopening a saved declaration shows a line for every section again (80C, 80D, NPS, home-loan interest, HRA, other), not only the sections already claimed, so a claim can be added in another section after the first save.
|
|
76
|
+
|
|
77
|
+
## [0.21.3] - 2026-10-09
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
- Phones: My attendance, the team calendar and an employee's attendance in admin no longer run wider than the screen once a month has punches; Sa/Su are back and check-in/check-out stack in each day.
|
|
81
|
+
- Phones: a long name or an email as the display name in the top bar no longer widens every screen and pushes the tab bar off.
|
|
82
|
+
- Phones: long links, file names and emails in policies, HR requests, appraisals, flashes and stacked tables (audit trail, approvals, team board, request lists) wrap instead of widening the page or hiding values.
|
|
83
|
+
- Admin employee profile with a salary card fits a phone; payroll and overview tiles go 2×2 below 1100px so amounts stay on one line beside the side rail.
|
|
84
|
+
|
|
10
85
|
## [0.21.2] - 2026-10-07
|
|
11
86
|
|
|
12
87
|
### Fixed
|
data/README.md
CHANGED
|
@@ -277,8 +277,9 @@ the audit row is the trail. Older days, off days, the third fix of a week, a cha
|
|
|
277
277
|
to a real punch, a day HR already regularized or rejected, or a fix that cannot
|
|
278
278
|
apply (no check-in that day) stay ordinary tickets for HR.
|
|
279
279
|
|
|
280
|
-
Home has an "
|
|
281
|
-
dates, so the team knows who is away and until when.
|
|
280
|
+
Home has an "On leave this week" card: everyone with approved leave in the current
|
|
281
|
+
Mon–Sun week, with the leave's dates, so the team knows who is away and until when.
|
|
282
|
+
It says nothing about attendance, and the leave type is not shown.
|
|
282
283
|
|
|
283
284
|
### Holidays and calendar
|
|
284
285
|
|
|
@@ -398,6 +399,57 @@ Override the CSS variables, nothing else:
|
|
|
398
399
|
:root { --hrl-accent: #00a24f; --hrl-font: "Inter", sans-serif; }
|
|
399
400
|
```
|
|
400
401
|
|
|
402
|
+
Every variable, with its role and engine default (all on `:root` in
|
|
403
|
+
`hr_lite/hr_lite.css`):
|
|
404
|
+
|
|
405
|
+
| Variable | Role | Default |
|
|
406
|
+
|---|---|---|
|
|
407
|
+
| `--hrl-font` | body and UI face | system stack |
|
|
408
|
+
| `--hrl-font-head` | page and card titles | `var(--hrl-font)` |
|
|
409
|
+
| `--hrl-t-micro` | badges, chips, legends, table heads, tab labels | `.75rem` |
|
|
410
|
+
| `--hrl-t-small` | hints, field labels, table cells, meta lines | `.875rem` |
|
|
411
|
+
| `--hrl-t-body` | body text, inputs (iOS zoom floor), buttons | `1rem` |
|
|
412
|
+
| `--hrl-t-lead` | card titles, the punch button | `1.125rem` |
|
|
413
|
+
| `--hrl-t-title` | page title on phones | `1.25rem` |
|
|
414
|
+
| `--hrl-t-display` | KPI values, page title from 768px | `1.5rem` |
|
|
415
|
+
| `--hrl-lh-tight` / `--hrl-lh-body` | line height of titles and badges / of body text | `1.25` / `1.5` |
|
|
416
|
+
| `--hrl-accent` | links, primary buttons, active nav | `#2563eb` |
|
|
417
|
+
| `--hrl-accent-ink` | text on accent | `#ffffff` |
|
|
418
|
+
| `--hrl-ink` | primary text | `#111827` |
|
|
419
|
+
| `--hrl-ink-2` | text on a tint (grid tags, muted badges) | `#374151` |
|
|
420
|
+
| `--hrl-muted` | secondary text on white or bg, never on a tint | `#4b5563` |
|
|
421
|
+
| `--hrl-bg` | page background | `#f4f5f7` |
|
|
422
|
+
| `--hrl-card` | card surface | `#ffffff` |
|
|
423
|
+
| `--hrl-line` | dividers, card borders | `#e5e7eb` |
|
|
424
|
+
| `--hrl-field` | input, select and textarea border (3:1 or better) | `#6b7280` |
|
|
425
|
+
| `--hrl-ok` / `--hrl-ok-bg` | present, approved | `#047857` / `#d1fae5` |
|
|
426
|
+
| `--hrl-warn` / `--hrl-warn-bg` | holiday, pending | `#b45309` / `#fef3c7` |
|
|
427
|
+
| `--hrl-bad` / `--hrl-bad-bg` | absent, rejected, errors | `#b91c1c` / `#fee2e2` |
|
|
428
|
+
| `--hrl-info-bg` | info tint, active nav, leave cell | `#eff6ff` |
|
|
429
|
+
| `--hrl-scrim` | backdrop behind the More sheet | `rgba(15, 23, 42, .32)` |
|
|
430
|
+
| `--hrl-s-1` `--hrl-s-2` `--hrl-s-3` `--hrl-s-4` `--hrl-s-5` `--hrl-s-6` `--hrl-s-8` `--hrl-s-10` `--hrl-s-12` | spacing steps | 4, 8, 12, 16, 20, 24, 32, 40, 48px |
|
|
431
|
+
| `--hrl-gutter` | phone screen padding | `.85rem` |
|
|
432
|
+
| `--hrl-target` | minimum tap target | `44px` |
|
|
433
|
+
| `--hrl-gap-target` | minimum gap between adjacent targets | `8px` |
|
|
434
|
+
| `--hrl-radius-sm` | controls, nav links, flash, grid cells | `12px` |
|
|
435
|
+
| `--hrl-radius` | cards, KPI tiles, tables | `16px` |
|
|
436
|
+
| `--hrl-radius-lg` | top corners of the More sheet | `20px` |
|
|
437
|
+
| `--hrl-radius-pill` | badges, chips, avatars, counts | `9999px` |
|
|
438
|
+
| `--hrl-shadow` | card elevation | `0 1px 3px` |
|
|
439
|
+
| `--hrl-shadow-md` / `--hrl-shadow-lg` | menus / dialogs | `0 6px 18px` / `0 18px 40px` |
|
|
440
|
+
| `--hrl-shadow-sheet` | the More sheet (shadow cast upward) | `0 -6px 18px` |
|
|
441
|
+
| `--hrl-focus` | focus ring colour | `var(--hrl-accent)` |
|
|
442
|
+
| `--hrl-focus-w` / `--hrl-focus-offset` | focus ring width / offset | `2px` / `2px` |
|
|
443
|
+
| `--hrl-ease` | easing for transitions | `cubic-bezier(.2, .6, .2, 1)` |
|
|
444
|
+
| `--hrl-dur-fast` / `--hrl-dur` | short / standard transition | `120ms` / `220ms` |
|
|
445
|
+
| `--hrl-z-sticky` / `--hrl-z-menu` / `--hrl-z-sheet` | app and tab bars / dropdowns / the More sheet | `20` / `30` / `40` |
|
|
446
|
+
|
|
447
|
+
The ID card also reads `--hrl-card-display` and `--hrl-card-body` (its fonts;
|
|
448
|
+
unset, both fall back to `--hrl-font`).
|
|
449
|
+
|
|
450
|
+
Leave-type badges (`.hrl-badge--type`) read `--hrl-type`, set inline per type;
|
|
451
|
+
it colours the dot only, never the text.
|
|
452
|
+
|
|
401
453
|
Point `config.extra_stylesheets` at a stylesheet and it is linked after the
|
|
402
454
|
engine's own CSS, so your `--hrl-*` overrides win. Every view is also
|
|
403
455
|
overridable through standard engine view precedence — drop a file at the same
|
|
@@ -19,13 +19,28 @@
|
|
|
19
19
|
if (!form || form.nodeName !== "FORM") return;
|
|
20
20
|
|
|
21
21
|
var message = form.getAttribute("data-turbo-confirm");
|
|
22
|
-
if (!message)
|
|
23
|
-
|
|
24
|
-
if (!window.confirm(message)) {
|
|
22
|
+
if (message && !window.confirm(message)) {
|
|
25
23
|
event.preventDefault();
|
|
26
24
|
event.stopPropagation();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Double-submit guard (data-disable-with is inert without Turbo/ujs). The
|
|
29
|
+
// timeout lets the submitter's value post first; geo punch runs its own.
|
|
30
|
+
if (!form.hasAttribute("data-hrl-geo-punch") && event.submitter) {
|
|
31
|
+
var b = event.submitter;
|
|
32
|
+
setTimeout(function () { b.disabled = true; b.setAttribute("aria-busy", "true"); }, 0);
|
|
27
33
|
}
|
|
28
34
|
},
|
|
29
35
|
true // capture, so the check runs before any other submit handler
|
|
30
36
|
);
|
|
37
|
+
|
|
38
|
+
// Back restores a submitted page from the bfcache with its button still locked.
|
|
39
|
+
window.addEventListener("pageshow", function (event) {
|
|
40
|
+
if (!event.persisted) return;
|
|
41
|
+
document.querySelectorAll("form:not([data-hrl-geo-punch]) [aria-busy]").forEach(function (b) {
|
|
42
|
+
b.disabled = false;
|
|
43
|
+
b.removeAttribute("aria-busy");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
31
46
|
})();
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// <input type="hidden" name="lat"><input type="hidden" name="lng">
|
|
5
5
|
// <input type="hidden" name="accuracy_m"><input type="hidden" name="geo_status">
|
|
6
6
|
// <button type="submit">…</button>
|
|
7
|
-
// <
|
|
7
|
+
// <p data-hrl-geo-status role="status" aria-live="polite"></p> (not hidden, or the first message is missed)
|
|
8
8
|
// </form>
|
|
9
9
|
// A denied permission holds the punch; timeout/unavailable submit anyway
|
|
10
10
|
// with geo_status set; the server flags them.
|
|
@@ -12,10 +12,27 @@
|
|
|
12
12
|
|
|
13
13
|
centre(document.querySelector(".hrl-side"));
|
|
14
14
|
|
|
15
|
+
// Chrome scrolls a focused field's caret into view, not the whole field, so a
|
|
16
|
+
// textarea near the bottom can sit half under the fixed tab bar. Nudge it out.
|
|
17
|
+
var tabbar = document.querySelector(".hrl-tabbar");
|
|
18
|
+
document.addEventListener("focusin", function (event) {
|
|
19
|
+
if (!tabbar || !tabbar.getClientRects().length || tabbar.contains(event.target)) return;
|
|
20
|
+
if (event.target.getBoundingClientRect().bottom > tabbar.getBoundingClientRect().top) {
|
|
21
|
+
event.target.scrollIntoView({ block: "nearest" });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
15
25
|
var more = document.querySelector(".hrl-tabbar__more");
|
|
16
26
|
if (more) {
|
|
17
27
|
more.addEventListener("toggle", function () {
|
|
18
28
|
if (more.open) centre(more.querySelector(".hrl-sheet"));
|
|
19
29
|
});
|
|
30
|
+
// Escape, or a tap on the scrim (the <details> itself), closes the sheet.
|
|
31
|
+
document.addEventListener("keydown", function (event) {
|
|
32
|
+
if (event.key === "Escape" && more.open) { more.open = false; more.querySelector("summary").focus(); }
|
|
33
|
+
});
|
|
34
|
+
document.addEventListener("click", function (event) {
|
|
35
|
+
if (more.open && !event.target.closest(".hrl-sheet, .hrl-tabbar__more > summary")) more.open = false;
|
|
36
|
+
});
|
|
20
37
|
}
|
|
21
38
|
})();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Dependency-free type-to-filter for long selects.
|
|
2
|
+
// Markup contract: <select data-hrl-filter="Type a name to filter">. A search
|
|
3
|
+
// box with that label goes in front of the select, and typing keeps only the
|
|
4
|
+
// options whose text matches. The select keeps its name and submits as before;
|
|
5
|
+
// without JS it stays a plain select. Options are removed, not hidden, because
|
|
6
|
+
// iOS Safari's picker ignores hidden options.
|
|
7
|
+
(function () {
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
function setup(select) {
|
|
11
|
+
var all = Array.prototype.slice.call(select.options);
|
|
12
|
+
var picked = select.value; // the stored pick, or the admin's own choice from the list
|
|
13
|
+
var input = document.createElement("input");
|
|
14
|
+
input.type = "search";
|
|
15
|
+
input.className = "hrl-input hrl-filter";
|
|
16
|
+
input.autocomplete = "off";
|
|
17
|
+
input.placeholder = select.getAttribute("data-hrl-filter") || "Type to filter";
|
|
18
|
+
input.setAttribute("aria-label", input.placeholder);
|
|
19
|
+
select.parentNode.insertBefore(input, select);
|
|
20
|
+
|
|
21
|
+
function filter() {
|
|
22
|
+
var q = input.value.trim().toLowerCase();
|
|
23
|
+
var value = q ? select.value : picked; // an empty box puts the stored pick back
|
|
24
|
+
var keep = all.filter(function (o) { return o.text.toLowerCase().indexOf(q) !== -1; });
|
|
25
|
+
if (!keep.length) return; // no match: leave the list as is, so the field still submits
|
|
26
|
+
select.replaceChildren.apply(select, keep);
|
|
27
|
+
// Keep the current pick while it still matches, else take the first match.
|
|
28
|
+
if (keep.some(function (o) { return o.value === value; })) select.value = value;
|
|
29
|
+
else select.selectedIndex = 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
select.addEventListener("change", function () { picked = select.value; });
|
|
33
|
+
input.addEventListener("input", filter);
|
|
34
|
+
input.addEventListener("keydown", function (e) {
|
|
35
|
+
if (e.key === "Enter") e.preventDefault(); // never submit the form half-filled
|
|
36
|
+
if (e.key === "Escape" && input.value) { e.preventDefault(); input.value = ""; filter(); }
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function init() {
|
|
41
|
+
document.querySelectorAll("select[data-hrl-filter]").forEach(setup);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init);
|
|
45
|
+
else init();
|
|
46
|
+
})();
|