@kernhq/module-hr 0.10.4 → 0.11.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.
- package/package.json +5 -5
- package/src/client/components/DayDetail.svelte +641 -0
- package/src/client/components/EmploymentChangeDialog.svelte +341 -0
- package/src/client/components/HrSidebar.svelte +7 -0
- package/src/client/components/LeaveLedgerPanel.svelte +654 -0
- package/src/client/components/PersonDocumentsSection.svelte +492 -0
- package/src/client/components/PersonJobSection.svelte +343 -0
- package/src/client/components/PersonPanel.svelte +23 -44
- package/src/client/components/PersonSensitiveSection.svelte +382 -0
- package/src/client/components/RegularizationDialog.svelte +334 -0
- package/src/client/components/refusal.ts +21 -0
- package/src/client/messages.ts +3391 -0
- package/src/client/mock.ts +1417 -89
- package/src/client/module.ts +50 -0
- package/src/client/pages/AttendancePage.svelte +116 -11
- package/src/client/pages/LeavePage.svelte +86 -5
- package/src/client/pages/OrgPage.svelte +1623 -0
- package/src/client/pages/leave-and-attendance.test.ts +29 -2
- package/src/client/query.ts +21 -0
- package/src/client/settings/AccrualSettings.svelte +1779 -0
- package/src/client/settings/ApprovalsSettings.svelte +1206 -0
- package/src/client/settings/PeriodsSettings.svelte +858 -0
|
@@ -198,7 +198,13 @@ const attendance = page('./AttendancePage.svelte')
|
|
|
198
198
|
const leave = page('./LeavePage.svelte')
|
|
199
199
|
|
|
200
200
|
/** A day sheet row, shaped enough for the `{#if}`s inside the month list. */
|
|
201
|
-
const day = { overtimeMinutes: 0, anomalies: [] as unknown[] }
|
|
201
|
+
const day = { overtimeMinutes: 0, anomalies: [] as unknown[], businessDate: '2026-08-03' }
|
|
202
|
+
/**
|
|
203
|
+
* What an expandable row reads besides the day itself: whether a correction is waiting on this
|
|
204
|
+
* date, and whether this row is the open one. Both live outside the `{#each}`, so the resolver has
|
|
205
|
+
* to be handed them or every render of the month throws.
|
|
206
|
+
*/
|
|
207
|
+
const row = { correctionDates: new Set<string>(), open: false }
|
|
202
208
|
|
|
203
209
|
describe('the month on the attendance page', () => {
|
|
204
210
|
/**
|
|
@@ -211,7 +217,7 @@ describe('the month on the attendance page', () => {
|
|
|
211
217
|
})
|
|
212
218
|
|
|
213
219
|
it('draws a day-shaped skeleton while the first fetch is in flight', () => {
|
|
214
|
-
const body = attendance.render('loading', { loading: true, days: [], daysQuery: {}, day })
|
|
220
|
+
const body = attendance.render('loading', { loading: true, days: [], daysQuery: {}, day, ...row })
|
|
215
221
|
expect(body).toContain('Skeleton')
|
|
216
222
|
expect(body).not.toContain('EmptyState')
|
|
217
223
|
})
|
|
@@ -227,6 +233,7 @@ describe('the month on the attendance page', () => {
|
|
|
227
233
|
days: [],
|
|
228
234
|
daysQuery: { isError: true },
|
|
229
235
|
day,
|
|
236
|
+
...row,
|
|
230
237
|
})
|
|
231
238
|
expect(body).toContain("t('attendance_error')")
|
|
232
239
|
expect(body).toContain("t('retry')")
|
|
@@ -239,6 +246,7 @@ describe('the month on the attendance page', () => {
|
|
|
239
246
|
days: [],
|
|
240
247
|
daysQuery: { isError: false },
|
|
241
248
|
day,
|
|
249
|
+
...row,
|
|
242
250
|
})
|
|
243
251
|
expect(body).toContain("t('attendance_none')")
|
|
244
252
|
expect(body).not.toContain("t('attendance_error')")
|
|
@@ -255,6 +263,7 @@ describe('the month on the attendance page', () => {
|
|
|
255
263
|
days: [{ id: 'a' }],
|
|
256
264
|
daysQuery: { isError: true },
|
|
257
265
|
day,
|
|
266
|
+
...row,
|
|
258
267
|
})
|
|
259
268
|
expect(body).toContain('{#each days as day (day.id)}')
|
|
260
269
|
expect(body).toContain("t('attendance_stale')")
|
|
@@ -268,10 +277,28 @@ describe('the month on the attendance page', () => {
|
|
|
268
277
|
days: [{ id: 'a' }],
|
|
269
278
|
daysQuery: { isError: false },
|
|
270
279
|
day,
|
|
280
|
+
...row,
|
|
271
281
|
})
|
|
272
282
|
expect(body).toContain('{#each days as day (day.id)}')
|
|
273
283
|
expect(body).not.toContain("t('attendance_stale')")
|
|
274
284
|
})
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* The anomaly badge used to be `{day.anomalies.length}` — a number in a warning tone with no
|
|
288
|
+
* noun beside it and nothing to click. It counts things a person has to look at, so it says so,
|
|
289
|
+
* and the sentences behind it are one row-click away.
|
|
290
|
+
*/
|
|
291
|
+
it('names what the anomaly badge counts rather than showing a bare number', () => {
|
|
292
|
+
const body = attendance.render('loading', {
|
|
293
|
+
loading: false,
|
|
294
|
+
days: [{ id: 'a' }],
|
|
295
|
+
daysQuery: { isError: false },
|
|
296
|
+
day: { ...day, anomalies: ['missing_clock_out'] },
|
|
297
|
+
...row,
|
|
298
|
+
})
|
|
299
|
+
expect(body).toContain("t('att_anomalies_count', { count: day.anomalies.length })")
|
|
300
|
+
expect(body).not.toContain('<Badge tone="warning">{day.anomalies.length}</Badge>')
|
|
301
|
+
})
|
|
275
302
|
})
|
|
276
303
|
|
|
277
304
|
describe('the attendance tiles', () => {
|
package/src/client/query.ts
CHANGED
|
@@ -50,6 +50,27 @@ export const hrKeys = {
|
|
|
50
50
|
entities: (ws: string) => ['hr', 'entities', ws] as const,
|
|
51
51
|
officePeople: (ws: string, officeId: string, primaryOnly: boolean) =>
|
|
52
52
|
['hr', 'office-people', ws, officeId, primaryOnly ? 'primary' : 'all'] as const,
|
|
53
|
+
/**
|
|
54
|
+
* The ledger is keyed by the leave type *and* the year as well as the person: the panel anchors
|
|
55
|
+
* its running balance on the balance the server computed for one entitlement year, so serving it
|
|
56
|
+
* another year's entries from cache would draw a column of numbers reconciling to nothing.
|
|
57
|
+
*/
|
|
58
|
+
leaveLedger: (ws: string, personId: string, leaveTypeId: string, periodYear: number) =>
|
|
59
|
+
['hr', 'leave-ledger', ws, personId, leaveTypeId, periodYear] as const,
|
|
60
|
+
employmentHistory: (ws: string, personId: string) => ['hr', 'employment-history', ws, personId] as const,
|
|
61
|
+
documents: (ws: string, personId: string) => ['hr', 'documents', ws, personId] as const,
|
|
62
|
+
/** Fetched only where the viewer holds `hr.person.view_sensitive`, so it is its own entry. */
|
|
63
|
+
sensitive: (ws: string, personId: string) => ['hr', 'sensitive', ws, personId] as const,
|
|
64
|
+
/**
|
|
65
|
+
* The org editor asks for archived units too, so it cannot share `orgUnits` with the chart —
|
|
66
|
+
* a toggle that changes what a query asks for has to change the key, or the cache answers the
|
|
67
|
+
* question it was asked last time and the switch appears to do nothing.
|
|
68
|
+
*/
|
|
69
|
+
orgUnitsAll: (ws: string) => ['hr', 'org-units', ws, 'with-archived'] as const,
|
|
70
|
+
positions: (ws: string) => ['hr', 'positions', ws, 'with-archived'] as const,
|
|
71
|
+
/** Every period in one read: `periods.list` returns no cursor, so there is nothing to page. */
|
|
72
|
+
periods: (ws: string) => ['hr', 'periods', ws] as const,
|
|
73
|
+
approvalChains: (ws: string) => ['hr', 'approval-chains', ws] as const,
|
|
53
74
|
} as const
|
|
54
75
|
|
|
55
76
|
/** `YYYY-MM-DD` for a date, in the viewer's own zone rather than UTC. */
|