Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
82850fd
Merge pull request #320 from aliansoftwareteam/main
parth0025 Jul 1, 2026
4e9065c
feat(dashboard): add Project Progress cards (AHE-3789)
parth0025 Jul 2, 2026
49b8f5c
Merge pull request #322 from aliansoftwareteam/feat/project-progress-…
parth0025 Jul 3, 2026
c348121
feat(settings): distinct nav icons for security and integration menus
parth0025 Jul 3, 2026
d50aca7
Merge pull request #324 from aliansoftwareteam/fix/settings-nav-icons…
parth0025 Jul 3, 2026
9156045
feat(dashboard): add resource-utilization cards
joshishiv4 Jul 3, 2026
b57b649
Merge branch 'staging' into enhance/dashboard
joshishiv4 Jul 3, 2026
4ba6297
fix: rename LiveWorkTableCard to ActiveWorkTableCard to avoid key col…
joshishiv4 Jul 3, 2026
757dda4
chore: add husky pre-commit and commit-msg hooks
joshishiv4 Jul 3, 2026
fda8faf
fix: use npx to resolve frontend eslint in lint-staged on windows
joshishiv4 Jul 3, 2026
e7568d1
fix: force lf line endings on husky hooks via gitattributes
joshishiv4 Jul 3, 2026
76433a1
Merge pull request #325 from aliansoftwareteam/feat/dashboard-resourc…
parth0025 Jul 3, 2026
4cfe8d5
refactor: use nodemailer SMTP transport in service.js
parth0025 Jul 3, 2026
a34c55b
Merge pull request #327 from aliansoftwareteam/refactor/service-nodem…
parth0025 Jul 3, 2026
e945234
feat(dashboard): on-leave card, project drill-downs, global date range
joshishiv4 Jul 3, 2026
afc32cc
feat(dashboard): tracker logged columns and on-leave ticket links
joshishiv4 Jul 3, 2026
0eb8991
Merge pull request #329 from aliansoftwareteam/feat/dashboard-onleave…
joshishiv4 Jul 3, 2026
7591aa2
fix: skip husky setup when devDependencies are omitted
joshishiv4 Jul 3, 2026
52c184f
Merge pull request #330 from aliansoftwareteam/fix/husky-prepare-prod…
parth0025 Jul 3, 2026
d8c888a
fix(dashboard): resolve CodeRabbit PR #328 findings
parth0025 Jul 3, 2026
7d8b44e
fix(mail): harden Nodemailer transport + accurate errors (CodeRabbit …
parth0025 Jul 3, 2026
00b5622
Merge pull request #331 from aliansoftwareteam/fix/dashboard-caller-s…
parth0025 Jul 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"permissions": {
"allow": [
"Bash(npm run *)"
"Bash(npm run *)",
"Bash(xargs grep -l \"apiRequest\\\\|fetch\\\\|axios\")"
]
}
}
72 changes: 72 additions & 0 deletions .claude/test-cases/AHE-3789-project-progress-cards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# AHE-3789 — Project-progress & resource dashboard cards

Five new **read-only** dashboard cards, added to the customizable card system.
All additive — no existing card, endpoint, or data path was modified.

> **Work by Category** (point 5) is the redesign of the earlier "Users by Work
> Category" prototype: **task count** per category (distinct tasks each user
> logged time on in the window), a **totals** row, and a team-split **summary
> bar**. All filters use the **standard edit-card settings modal** (Projects /
> Teams-Users / Include-subtasks) plus a category→task-type **template** editor
> embedded in that same modal — no separate config modal. Unmapped task types
> are **ignored** (no "Uncategorized"). **Active Time Trackers** (formerly "Live
> Work") is a table with a tracker-memo column.
**Cards**
| Card key | Title | Source |
|----------|-------|--------|
| `ActiveProjectsCard` | Active Projects | `metric: active_projects` (company-wide count) |
| `ProjectsByTypeCard` | Projects by Type | `metric: projects_by_type` (company-wide) |
| `RunningProjectsCard` | Running Projects | `metric: running_projects` (period) |
| `LiveWorkTableCard` | Active Time Trackers | `metric: live_work` — who's tracking now + task/project + tracker memo |
| `UsersByCategoryCard` | Work by Category | `metric: users_by_category` — task count per user, bucketed into user-defined categories |

**Files**
- Backend: `Modules/UserDashboard/controller.js` (`getProjectProgressMetric`), `routes.js` (`POST /api/v1/dashboard/project-metrics`)
- Frontend: `ProjectMetricsCard.vue` (Active Projects, Projects by Type), `ProjectResourceCard.vue` (Running Projects), `LiveWorkCard.vue` (Active Time Trackers), `UsersByCategoryCard.vue` (Work by Category), `CategoryTaskTypeMapper.vue` (category template, embedded in the edit-card modal), `CardFieldComponent.vue` (renders the mapper for this card), `DashBoardCard.vue` (header period + refresh), `HomePage.vue` (register/wire), `utils/cardComponent.json`, `composable/commonFunction.js`, `locales/en.js`

---

## Prerequisites
1. **Restart the backend** (catalog is `require`d from `cardComponent.json` at boot).
2. Frontend dev server / built app.
3. **Log in as Owner/Admin (roleType 1/2)** — Running Projects, Active Time Trackers & Work by Category are role-scoped for non-admins.
4. Seed: ≥ 3 active projects w/ different `ProjectType` + ≥ 1 closed; time logged today/this week across ≥ 2 task types; a running tracker (with a memo).

---

## Test cases

| ID | Card / area | Steps | Expected | Status |
|----|-------------|-------|----------|:--:|
| PPC-01 | Catalog | Add Card | "Project Progress" category lists **5** cards, readable titles/descriptions. ||
| PPC-02 | Active Projects | Add | Company-wide count (`statusType !== 'close'`, not deleted); matches DB `activeProjects`. ||
| PPC-03 | Projects by Type | Add | Bars per `ProjectType` sum to Active count; untyped → "Unspecified". ||
| PPC-04 | Running Projects | Header period Today → wider | Distinct active projects with logged time in the period; grows for wider window; persists. ||
| PPC-05 | Running Projects | Log time in a closed project | Not counted (active only). ||
| PPC-06 | Active Time Trackers | Start a tracker (with memo) → refresh | Table row: name + live dot, task, project, **Working on** memo. Clicking the task opens the **TaskDetail sidebar**. ||
| PPC-07 | Active Time Trackers | Header **N users tracking** + **user search** | Count = distinct users; table filters by user name; stop tracker + refresh → row leaves. ||
| PPC-08 | Role — member | Non-admin views the activity cards | Reflects only **their** activity (role-scoped). ||
| PPC-09 | Header UI | All cards | Refresh re-fetches; skeleton while loading; period dropdown (Running Projects, Work by Category) sits before the gear; cards resize narrow without the header breaking. ||
| PPC-10 | Regression | Existing cards + add/edit/remove/drag | Work as before; **no console errors**. ||
| PPC-11 | Boot integrity | Restart backend; `GET /api/v1/cardcomponent` | Returns **31** cards; no JSON parse error. ||
| PPC-12 | Multi-tenant | Second company | Each card shows only the current company's data. ||
| WBC-01 | Work by Category — first add | Add the card | Shows a **"Set up categories"** prompt pointing to the **⚙ settings** (no template yet). ||
| WBC-02 | Settings — template | Card **settings (⚙)****Category template** → pick **Development**, tick 2 task types; pick **QA**, tick 1 → **Save** | Table columns appear per non-empty category; each ticked type belongs to exactly **one** category (re-ticking moves it). Template **persists** after reload. ||
| WBC-03 | Data correctness | With time logged across the mapped types | Per-user rows show the **count of distinct tasks** they logged in each category (centered under each column header); **tfoot Total row** = column sums; summary bar segments match the category totals. ||
| WBC-04 | Unmapped types | Log time on a task whose type isn't mapped to any category | It is **not** counted anywhere — no "Uncategorized" column; only mapped-category tasks appear. ||
| WBC-05 | Settings — projects | Settings (⚙) → **Location** (project) picker → choose a subset → Save | Only the selected projects' logged time counts. ||
| WBC-06 | Settings — teams/users | Settings (⚙) → **Show Assignees** → pick a team and/or users → Save | Only those users' time counts (team expands to member ids). ||
| WBC-07 | Settings — subtasks | Settings (⚙) → **Include subtasks** off → Save | Time logged on subtasks (`isParentTask:false`) is excluded. ||
| WBC-08 | Period + refresh | Change header period; click refresh | Re-fetches for the window; period persists on the card. ||
| WBC-09 | Sorting | Click column headers | Rows sort by user / any category / total (asc↔desc). ||
| WBC-10 | Role — member | Non-admin views the card | Only **their** logged time, still bucketed by the template. ||

---

## Notes
- **Active Projects / Projects by Type** — server-side, company-wide (`statusType !== 'close'`, not deleted).
- **Running Projects** — distinct active projects with logged time in the period; role-scoped; header period dropdown.
- **Active Time Trackers** — trackers running within the last **10 min**; **Working on** = the tracker's `LogDescription`; user count + user search + click-to-open TaskDetail; refresh via header icon.
- **Work by Category** — per user, the **count of distinct tasks** they logged time on in the window, per category (bucketed via the task's `TaskType` against `categoryMap`); unmapped types are **ignored** (no uncategorized). **All filters live in the standard edit-card settings modal** (⚙): Projects (`projectId`/Location), Teams-Users (`AssigneeUserId`/Show Assignees), Include-subtasks (`isParentTask` toggle), and the **category template** via the embedded `CategoryTaskTypeMapper` — saved into `cardData` through the normal card-config submit path (no custom modal). Team ids (`tId_*`) expand to member user ids before the request. Period + refresh in the card chrome (default This Week); role-scoped.
- All queries are read-only and companyId-scoped.
85 changes: 85 additions & 0 deletions .claude/test-cases/DashboardEnhancements-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Dashboard Enhancements v2 — On Leave card, drill-downs, period dropdowns, global date range

Four additive dashboard features on the home page. No existing endpoint semantics changed;
all new backend reads are companyId-scoped and read-only.

**Features**
1. **On Leave card** (`OnLeaveCard`) — leaves are managed as tickets in a PMS project
(e.g. *Support → HR Support*). Card settings pick that project + the status(es) that
mean "Leave approved". Card lists the tickets whose leave period (startDate–DueDate)
overlaps the selected window, plus **AB/PR** headcounts:
**AB (Absent)** = distinct applicants (first assignee of each ticket) · **PR (Present)** =
active company members − AB.
2. **Project-count drill-downs** — Project Pulse (Active / Working counters + each type-mix
bar), Active Projects, Projects by Type (each bar), Running Projects: clicking opens a
modal listing the projects behind the number with **type + status** (+ *worked in period*
for Project Pulse).
3. **Header period dropdown** — Project Pulse, Worked Tasks, Team Effort Breakdown,
Team Logged vs ETA now use the card-header period `<select>` (like Running Projects)
instead of a static "This Week" label.
4. **Global date range** — a from/to date picker at the top of the dashboard. Every
period dropdown gains an **Auto** option (timerange 0): Auto cards follow the global
range; the others keep their own preset. The global range persists per user
(localStorage `dashboardGlobalRange_<userId>`), default = this week.

**Files**
- Backend: `Modules/UserDashboard/controller.js` (`getOnLeaveBoard`, `includeProjects`
support in `getProjectUtilizationSummary` + `getProjectProgressMetric`),
`routes.js` (`POST /api/v1/dashboard/on-leave`)
- Catalog: `utils/cardComponent.json` (OnLeaveCard entry; `auto_range` option on the four
resource-card timerange fields)
- Frontend: `OnLeaveCard.vue`, `ProjectListModal.vue` (new); `ProjectPulseCard.vue`,
`ProjectMetricsCard.vue`, `ProjectResourceCard.vue`, `WorkedTasksTableCard.vue`,
`TeamCategoryBreakdownCard.vue`, `TeamLoggedVsEtaCard.vue`, `UsersByCategoryCard.vue`
(drill-down / auto / label removal); `HomePage.vue` (range bar, provide, period cards);
`useResourceWorkload.js` (`resolveCardRange`), `commonFunction.js` (card size),
`locales/en.js`

## Prerequisites
1. **Restart the backend** (catalog is `require`d from `cardComponent.json` at boot).
2. Log in; have a project holding leave tickets with an "Approved" status, tickets with
start/due dates in the current week.

## Test cases

| ID | Area | Steps | Expected | Status |
|----|------|-------|----------|:--:|
| OLV-01 | Catalog | Add Card → Resource Utilization | "On Leave" card listed with title/description. ||
| OLV-02 | Setup | Add without configuring | Card shows the "pick the leave project" hint. ||
| OLV-03 | Config | Settings ⚙ → Location = HR/Support project, Status = Approved → Save | Tickets overlapping the period appear: applicant (first assignee) avatar+name, ticket key/title, period (start – due), status chip in the status colour. ||
| OLV-04 | AB/PR | With N distinct applicants on leave in range | AB = N; PR = active company members − N; Leave Tickets = row count. ||
| OLV-05 | Overlap | Ticket spanning the whole window; ticket starting inside; ticket ending inside; ticket with no dates | First three counted; the dateless one excluded. ||
| OLV-06 | Period | Header dropdown Today → This Month | Re-fetches; wider window ⊇ narrower; selection persists on reload. ||
| DRL-01 | Project Pulse | Click the **Active** counter | Modal lists all active projects (name, type incl. In House by "IH" prefix, status, worked-in-period dot); count matches the counter. ||
| DRL-02 | Project Pulse | Click the **Working** counter | Modal shows only projects with logged time in the period. ||
| DRL-03 | Project Pulse | Click a type-mix bar (e.g. Hourly) | Modal shows only that type; row count = bar value. ||
| DRL-04 | Active Projects card | Click the number | Modal lists the active projects; count matches. ||
| DRL-05 | Projects by Type card | Click a bar | Modal filtered to that ProjectType. ||
| DRL-06 | Running Projects card | Click the number | Modal lists active projects with logged time in the selected period. ||
| DRL-07 | Modal UX | Esc / backdrop / ✕ | Modal closes; card unaffected; no console errors. ||
| DRL-08 | Modal loading | Open a drill-down on a slow network | Shimmer **skeleton rows** (with table headers) show while loading; count in the title appears only after load. ||
| DRL-09 | Status colours | Projects with different statuses in the modal | Each status renders a **coloured dot + status name** from the project's own `projectStatusData` palette (`textColor`); unmatched statuses fall back to a grey dot + humanized raw value. ||
| PDD-01 | Period dropdowns | Project Pulse / Worked Tasks / Team Effort / Team Logged vs ETA | Header shows a period `<select>` (defaults: Today / This Week / This Week / This Week); the old in-card period label is gone. ||
| PDD-02 | Persistence | Change a period, reload | Selection persisted (cardData.timerange) and data reflects it. ||
| PDD-03 | Settings parity | Same timerange in settings ⚙ | Settings dropdown shows the value picked in the header (incl. Auto) and vice-versa. ||
| GDR-01 | Global range | Dashboard top bar | Single **range picker** (CalenderCompo, same as timesheets): one input opens a two-date calendar with Current Week / Current Month presets and Apply/Cancel; default = this week; persists per user across reloads. ||
| GDR-02 | Auto mode | Set a card's period to **Auto**, change the global range → Apply | Card re-fetches for the new window; non-Auto cards don't. ||
| GDR-03 | Validation | Try to Apply with only one date picked / cancel mid-pick | Apply stays disabled until both dates are chosen; Cancel restores the previous range; future dates are selectable (needed for upcoming leaves). ||
| GDR-04 | Cards with Auto | Running Projects, Work by Category, Project Pulse, Worked Tasks, Team Effort, Team Logged vs ETA, On Leave | All expose Auto and honour the global range. ||
| OLV-07 | Avatars | Users with and without profile photos in the On Leave list | Photos render via the UserProfile atom (store `Employee_profileImageURL`, Wasabi keys handled); users without a photo get the default avatar — never a broken image. ||
| OLV-08 | Ticket link | Click a ticket key/name in the On Leave list | The **TaskDetail sidebar** opens for that leave ticket (same as Active Time Trackers); closing it returns to the intact card. ||
| PDD-04 | Refresh icons | All cards added in the recent dashboard PRs (Pulse, Active Work, Free Resources, Worked Tasks, Team Effort, Team Logged vs ETA, Tasks by Status/Project, Total Tasks, On Leave, …) | Header shows the refresh icon; clicking re-fetches that card only. ||
| PDD-05 | Card skeletons | Reload the dashboard on a slow network | Every self-fetching card shows a shimmer **skeleton** while loading (shared `CardSkeleton` atom; counter blocks on Project Pulse / On Leave) — no bare "…" placeholders anywhere. ||
| REG-01 | Regression | Existing cards, add/edit/remove/drag, refresh icons | Behave as before; `GET /api/v1/cardcomponent` returns 32 cards; no JSON parse error; no console errors. ||
| REG-02 | Multi-tenant | Second company | On-leave rows/headcounts and drill-down lists show only that company's data. ||

## Notes / assumptions
- **AB/PR** is interpreted as **Absent / Present** headcounts (attendance shorthand). The
applicant is the ticket's **first assignee** — matches the HR-Support convention where
the requester is assignee #1 and approvers are added after. If your workflow differs
(e.g. creator = applicant), change `getOnLeaveBoard`'s `AssigneeUserId[0]` pick.
- On-leave board is **not role-gated** (same as the utilization summary): who-is-on-leave
is team-visible information.
- Drill-down uses the same endpoints with `includeProjects: true` — no new list endpoints.
- The four resource cards keep their settings-modal timerange field; header dropdown and
settings write the same `cardData.timerange`.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Git hooks are executed by sh — CRLF line endings break them on Windows
# ("husky - command not found"), so force LF regardless of core.autocrlf.
.husky/* text eol=lf
1 change: 1 addition & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx --no -- commitlint --edit "$1"
14 changes: 14 additions & 0 deletions .husky/install.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Husky bootstrap — runs from the package.json "prepare" script.
// Production/CI installs omit devDependencies, so husky isn't present there;
// requiring it directly made `npm install` fail on the deploy server
// (sh: husky: not found, exit 127). Skip silently in that case — git hooks
// are a dev-machine concern only.
if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') {
process.exit(0);
}
try {
const { default: husky } = await import('husky');
console.log(husky());
} catch {
// husky not installed (devDependencies omitted) — nothing to set up.
}
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx lint-staged
29 changes: 29 additions & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Validate the branch name before pushing — mirrors
# .github/workflows/branch-name.yml so the failure happens locally
# instead of on the PR. Keep the patterns in sync with that workflow
# and BRANCHING.md § Topic branches.

BRANCH=$(git rev-parse --abbrev-ref HEAD)

STANDARD='^(feat|fix|hotfix|refactor|chore|docs|perf|test|ci|build|style)/[a-z0-9]+(-[a-z0-9.]+)*$'
RELEASE='^release/v[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9.-]+)?$'
BACKPORT='^hotfix-backport/[a-z0-9]+(-[a-z0-9.]+)*$'
BOT='^(dependabot|renovate)/.+$'
LONG_RUNNING='^(staging|main)$'

for pattern in "$STANDARD" "$RELEASE" "$BACKPORT" "$BOT" "$LONG_RUNNING"; do
if echo "$BRANCH" | grep -Eq "$pattern"; then
exit 0
fi
done

echo "❌ Branch name '$BRANCH' does not follow the convention."
echo ""
echo "Expected: <type>/<short-kebab-case-description>"
echo "Allowed types: feat, fix, hotfix, refactor, chore, docs, perf, test, ci, build, style"
echo ""
echo "Examples: feat/employee-workload-report fix/login-validation-error"
echo ""
echo "See BRANCHING.md (§ Topic branches). CI enforces this on every PR"
echo "(.github/workflows/branch-name.yml), so pushing would fail there anyway."
exit 1
Loading
Loading