@burdenoff/microfe-crewfoundry 2026.1030.3 → 2026.1102.1
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/dist/crewfoundry/CrewFoundryRoutes.d.ts.map +1 -1
- package/dist/crewfoundry/CrewFoundryRoutes.js +18 -14
- package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
- package/dist/crewfoundry/components/EmployeeSkillsPanel.d.ts +9 -0
- package/dist/crewfoundry/components/EmployeeSkillsPanel.d.ts.map +1 -1
- package/dist/crewfoundry/components/EmployeeSkillsPanel.js +111 -77
- package/dist/crewfoundry/components/EmployeeSkillsPanel.js.map +1 -1
- package/dist/crewfoundry/components/skills/FindPeopleBySkillCard.d.ts +13 -0
- package/dist/crewfoundry/components/skills/FindPeopleBySkillCard.d.ts.map +1 -0
- package/dist/crewfoundry/components/skills/FindPeopleBySkillCard.js +128 -0
- package/dist/crewfoundry/components/skills/FindPeopleBySkillCard.js.map +1 -0
- package/dist/crewfoundry/components/skills/MergeSkillDialog.d.ts +15 -0
- package/dist/crewfoundry/components/skills/MergeSkillDialog.d.ts.map +1 -0
- package/dist/crewfoundry/components/skills/MergeSkillDialog.js +58 -0
- package/dist/crewfoundry/components/skills/MergeSkillDialog.js.map +1 -0
- package/dist/crewfoundry/components/skills/RoleSkillMatchPanel.d.ts +15 -0
- package/dist/crewfoundry/components/skills/RoleSkillMatchPanel.d.ts.map +1 -0
- package/dist/crewfoundry/components/skills/RoleSkillMatchPanel.js +163 -0
- package/dist/crewfoundry/components/skills/RoleSkillMatchPanel.js.map +1 -0
- package/dist/crewfoundry/components/skills/SkillPicker.d.ts +20 -0
- package/dist/crewfoundry/components/skills/SkillPicker.d.ts.map +1 -0
- package/dist/crewfoundry/components/skills/SkillPicker.js +73 -0
- package/dist/crewfoundry/components/skills/SkillPicker.js.map +1 -0
- package/dist/crewfoundry/components/skills/SkillRelationsDialog.d.ts +13 -0
- package/dist/crewfoundry/components/skills/SkillRelationsDialog.d.ts.map +1 -0
- package/dist/crewfoundry/components/skills/SkillRelationsDialog.js +156 -0
- package/dist/crewfoundry/components/skills/SkillRelationsDialog.js.map +1 -0
- package/dist/crewfoundry/lib/analytics.d.ts +1 -29
- package/dist/crewfoundry/lib/analytics.d.ts.map +1 -1
- package/dist/crewfoundry/lib/analytics.js +3 -48
- package/dist/crewfoundry/lib/analytics.js.map +1 -1
- package/dist/crewfoundry/lib/skillMatching.d.ts +70 -0
- package/dist/crewfoundry/lib/skillMatching.d.ts.map +1 -0
- package/dist/crewfoundry/lib/skillMatching.js +73 -0
- package/dist/crewfoundry/lib/skillMatching.js.map +1 -0
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts +8 -0
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +468 -212
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +210 -177
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +6 -6
- package/dist/crewfoundry/pages/HrSkillsTaxonomyPagePage.d.ts +9 -0
- package/dist/crewfoundry/pages/HrSkillsTaxonomyPagePage.d.ts.map +1 -0
- package/dist/crewfoundry/pages/HrSkillsTaxonomyPagePage.js +456 -0
- package/dist/crewfoundry/pages/HrSkillsTaxonomyPagePage.js.map +1 -0
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.d.ts.map +1 -1
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +50 -102
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.d.ts +145 -0
- package/dist/crewfoundry/store/crewfoundryStore.d.ts.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +188 -57
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ranking people for an open role from canonical skill matches (BOFF-10361,
|
|
3
|
+
* mock cf-19).
|
|
4
|
+
*
|
|
5
|
+
* The backend's `crewEmployeesBySkill` already resolves each skill through
|
|
6
|
+
* aliases and IMPLIES / SUPERSEDES edges and explains every match. This
|
|
7
|
+
* module only combines the per-skill answers for a role's requirements into
|
|
8
|
+
* one ranked list: required skills weigh twice as much as nice-to-haves,
|
|
9
|
+
* then a stronger match type (EXACT > SUPERSEDED > IMPLIED) and a higher
|
|
10
|
+
* assessed proficiency break ties. Pure functions, no I/O.
|
|
11
|
+
*/
|
|
12
|
+
/** One skill a role asks for. */
|
|
13
|
+
export interface RoleSkillRequirement {
|
|
14
|
+
skillId: string;
|
|
15
|
+
skillName: string;
|
|
16
|
+
required: boolean;
|
|
17
|
+
minProficiency: number | null;
|
|
18
|
+
}
|
|
19
|
+
/** One person who can do one skill, as returned by crewEmployeesBySkill. */
|
|
20
|
+
export interface SkillHolder {
|
|
21
|
+
employee: {
|
|
22
|
+
id: string;
|
|
23
|
+
firstName: string;
|
|
24
|
+
lastName: string;
|
|
25
|
+
position: string;
|
|
26
|
+
department: string;
|
|
27
|
+
};
|
|
28
|
+
matchType: string;
|
|
29
|
+
matchedSkill: {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
};
|
|
33
|
+
proficiency: number | null;
|
|
34
|
+
explanation: string;
|
|
35
|
+
}
|
|
36
|
+
export interface RoleMatchedSkill {
|
|
37
|
+
skillId: string;
|
|
38
|
+
skillName: string;
|
|
39
|
+
required: boolean;
|
|
40
|
+
matchType: string;
|
|
41
|
+
viaSkill: string;
|
|
42
|
+
proficiency: number | null;
|
|
43
|
+
explanation: string;
|
|
44
|
+
}
|
|
45
|
+
export interface RoleMatch {
|
|
46
|
+
employeeId: string;
|
|
47
|
+
name: string;
|
|
48
|
+
detail: string;
|
|
49
|
+
/** 0-100: weighted share of the role's skills this person covers. */
|
|
50
|
+
matchPercent: number;
|
|
51
|
+
requiredCovered: number;
|
|
52
|
+
requiredTotal: number;
|
|
53
|
+
matched: RoleMatchedSkill[];
|
|
54
|
+
missingRequired: string[];
|
|
55
|
+
}
|
|
56
|
+
/** Strength of a match type; unknown types rank below every known one. */
|
|
57
|
+
export declare function matchStrength(matchType: string): number;
|
|
58
|
+
/**
|
|
59
|
+
* Combine per-skill holder lists into a ranked list of people for a role.
|
|
60
|
+
* `holdersBySkill` maps a requirement's skillId to the people who can do it
|
|
61
|
+
* (already filtered by that requirement's minimum proficiency). People who
|
|
62
|
+
* cover none of the role's skills never appear.
|
|
63
|
+
*/
|
|
64
|
+
export declare function rankRoleMatches(requirements: readonly RoleSkillRequirement[], holdersBySkill: ReadonlyMap<string, readonly SkillHolder[]>, limit?: number): RoleMatch[];
|
|
65
|
+
/** Skills whose names, slugs or aliases contain the query (case-insensitive), best first. */
|
|
66
|
+
export declare function searchSkills<T extends {
|
|
67
|
+
name: string;
|
|
68
|
+
aliases: string[];
|
|
69
|
+
}>(skills: readonly T[], query: string, limit?: number): T[];
|
|
70
|
+
//# sourceMappingURL=skillMatching.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillMatching.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/lib/skillMatching.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,iCAAiC;AACjC,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE;QACR,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAMD,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAwBD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,SAAS,oBAAoB,EAAE,EAC7C,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC,EAC3D,KAAK,SAAI,GACR,SAAS,EAAE,CA2Db;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,EACxE,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,SAAI,GACR,CAAC,EAAE,CAkBL"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region src/crewfoundry/lib/skillMatching.ts
|
|
2
|
+
var e = {
|
|
3
|
+
EXACT: 3,
|
|
4
|
+
SUPERSEDED: 2,
|
|
5
|
+
IMPLIED: 1
|
|
6
|
+
}, t = 2, n = 1;
|
|
7
|
+
function r(t) {
|
|
8
|
+
return e[t] ?? 0;
|
|
9
|
+
}
|
|
10
|
+
var i = (e) => e.required ? t : n;
|
|
11
|
+
function a(e) {
|
|
12
|
+
let t = e.filter((e) => e.proficiency !== null);
|
|
13
|
+
return t.length === 0 ? -1 : t.reduce((e, t) => e + (t.proficiency ?? 0), 0) / t.length;
|
|
14
|
+
}
|
|
15
|
+
function o(e, t) {
|
|
16
|
+
if (e.matchPercent !== t.matchPercent) return t.matchPercent - e.matchPercent;
|
|
17
|
+
if (e.requiredCovered !== t.requiredCovered) return t.requiredCovered - e.requiredCovered;
|
|
18
|
+
let n = e.matched.reduce((e, t) => e + r(t.matchType), 0), i = t.matched.reduce((e, t) => e + r(t.matchType), 0);
|
|
19
|
+
if (n !== i) return i - n;
|
|
20
|
+
let o = a(t.matched) - a(e.matched);
|
|
21
|
+
return o === 0 ? e.name.localeCompare(t.name) : o;
|
|
22
|
+
}
|
|
23
|
+
function s(e, t, n = 6) {
|
|
24
|
+
if (e.length === 0) return [];
|
|
25
|
+
let a = e.reduce((e, t) => e + i(t), 0), s = e.filter((e) => e.required).length, c = /* @__PURE__ */ new Map();
|
|
26
|
+
for (let n of e) for (let e of t.get(n.skillId) ?? []) {
|
|
27
|
+
let t = c.get(e.employee.id) ?? {
|
|
28
|
+
holder: e.employee,
|
|
29
|
+
matched: /* @__PURE__ */ new Map()
|
|
30
|
+
}, i = t.matched.get(n.skillId), a = {
|
|
31
|
+
skillId: n.skillId,
|
|
32
|
+
skillName: n.skillName,
|
|
33
|
+
required: n.required,
|
|
34
|
+
matchType: e.matchType,
|
|
35
|
+
viaSkill: e.matchedSkill.name,
|
|
36
|
+
proficiency: e.proficiency,
|
|
37
|
+
explanation: e.explanation
|
|
38
|
+
};
|
|
39
|
+
(!i || r(a.matchType) > r(i.matchType) || r(a.matchType) === r(i.matchType) && (a.proficiency ?? -1) > (i.proficiency ?? -1)) && t.matched.set(n.skillId, a), c.set(e.employee.id, t);
|
|
40
|
+
}
|
|
41
|
+
let l = [];
|
|
42
|
+
for (let [t, { holder: n, matched: r }] of c) {
|
|
43
|
+
let o = e.map((e) => r.get(e.skillId)).filter((e) => e !== void 0), c = e.filter((e) => r.has(e.skillId)).reduce((e, t) => e + i(t), 0);
|
|
44
|
+
l.push({
|
|
45
|
+
employeeId: t,
|
|
46
|
+
name: `${n.firstName} ${n.lastName}`.trim(),
|
|
47
|
+
detail: [n.position, n.department].filter(Boolean).join(" · "),
|
|
48
|
+
matchPercent: Math.round(c / a * 100),
|
|
49
|
+
requiredCovered: o.filter((e) => e.required).length,
|
|
50
|
+
requiredTotal: s,
|
|
51
|
+
matched: o,
|
|
52
|
+
missingRequired: e.filter((e) => e.required && !r.has(e.skillId)).map((e) => e.skillName)
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return l.sort(o).slice(0, Math.max(0, n));
|
|
56
|
+
}
|
|
57
|
+
function c(e, t, n = 8) {
|
|
58
|
+
let r = t.trim().toLowerCase();
|
|
59
|
+
if (!r) return [];
|
|
60
|
+
let i = [];
|
|
61
|
+
for (let t of e) {
|
|
62
|
+
let e = t.name.toLowerCase(), n = -1;
|
|
63
|
+
e === r ? n = 0 : e.startsWith(r) ? n = 1 : t.aliases.some((e) => e.toLowerCase() === r) ? n = 2 : e.includes(r) ? n = 3 : t.aliases.some((e) => e.toLowerCase().includes(r)) && (n = 4), n >= 0 && i.push({
|
|
64
|
+
skill: t,
|
|
65
|
+
score: n
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return i.sort((e, t) => e.score - t.score || e.skill.name.localeCompare(t.skill.name)).slice(0, n).map((e) => e.skill);
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { s as rankRoleMatches, c as searchSkills };
|
|
72
|
+
|
|
73
|
+
//# sourceMappingURL=skillMatching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillMatching.js","names":[],"sources":["../../../src/crewfoundry/lib/skillMatching.ts"],"sourcesContent":["/**\n * Ranking people for an open role from canonical skill matches (BOFF-10361,\n * mock cf-19).\n *\n * The backend's `crewEmployeesBySkill` already resolves each skill through\n * aliases and IMPLIES / SUPERSEDES edges and explains every match. This\n * module only combines the per-skill answers for a role's requirements into\n * one ranked list: required skills weigh twice as much as nice-to-haves,\n * then a stronger match type (EXACT > SUPERSEDED > IMPLIED) and a higher\n * assessed proficiency break ties. Pure functions, no I/O.\n */\n\n/** One skill a role asks for. */\nexport interface RoleSkillRequirement {\n skillId: string;\n skillName: string;\n required: boolean;\n minProficiency: number | null;\n}\n\n/** One person who can do one skill, as returned by crewEmployeesBySkill. */\nexport interface SkillHolder {\n employee: {\n id: string;\n firstName: string;\n lastName: string;\n position: string;\n department: string;\n };\n matchType: string;\n matchedSkill: { id: string; name: string };\n proficiency: number | null;\n explanation: string;\n}\n\nexport interface RoleMatchedSkill {\n skillId: string;\n skillName: string;\n required: boolean;\n matchType: string;\n viaSkill: string;\n proficiency: number | null;\n explanation: string;\n}\n\nexport interface RoleMatch {\n employeeId: string;\n name: string;\n detail: string;\n /** 0-100: weighted share of the role's skills this person covers. */\n matchPercent: number;\n requiredCovered: number;\n requiredTotal: number;\n matched: RoleMatchedSkill[];\n missingRequired: string[];\n}\n\nconst MATCH_STRENGTH: Record<string, number> = { EXACT: 3, SUPERSEDED: 2, IMPLIED: 1 };\nconst REQUIRED_WEIGHT = 2;\nconst NICE_TO_HAVE_WEIGHT = 1;\n\n/** Strength of a match type; unknown types rank below every known one. */\nexport function matchStrength(matchType: string): number {\n return MATCH_STRENGTH[matchType] ?? 0;\n}\n\nconst weightOf = (requirement: RoleSkillRequirement): number =>\n requirement.required ? REQUIRED_WEIGHT : NICE_TO_HAVE_WEIGHT;\n\nfunction averageProficiency(matched: RoleMatchedSkill[]): number {\n const assessed = matched.filter((item) => item.proficiency !== null);\n if (assessed.length === 0) return -1;\n return assessed.reduce((sum, item) => sum + (item.proficiency ?? 0), 0) / assessed.length;\n}\n\nfunction compareMatches(left: RoleMatch, right: RoleMatch): number {\n if (left.matchPercent !== right.matchPercent) return right.matchPercent - left.matchPercent;\n if (left.requiredCovered !== right.requiredCovered) {\n return right.requiredCovered - left.requiredCovered;\n }\n const leftStrength = left.matched.reduce((sum, item) => sum + matchStrength(item.matchType), 0);\n const rightStrength = right.matched.reduce((sum, item) => sum + matchStrength(item.matchType), 0);\n if (leftStrength !== rightStrength) return rightStrength - leftStrength;\n const proficiencyDelta = averageProficiency(right.matched) - averageProficiency(left.matched);\n if (proficiencyDelta !== 0) return proficiencyDelta;\n return left.name.localeCompare(right.name);\n}\n\n/**\n * Combine per-skill holder lists into a ranked list of people for a role.\n * `holdersBySkill` maps a requirement's skillId to the people who can do it\n * (already filtered by that requirement's minimum proficiency). People who\n * cover none of the role's skills never appear.\n */\nexport function rankRoleMatches(\n requirements: readonly RoleSkillRequirement[],\n holdersBySkill: ReadonlyMap<string, readonly SkillHolder[]>,\n limit = 6\n): RoleMatch[] {\n if (requirements.length === 0) return [];\n const totalWeight = requirements.reduce((sum, requirement) => sum + weightOf(requirement), 0);\n const requiredTotal = requirements.filter((requirement) => requirement.required).length;\n\n const people = new Map<\n string,\n { holder: SkillHolder['employee']; matched: Map<string, RoleMatchedSkill> }\n >();\n for (const requirement of requirements) {\n for (const holder of holdersBySkill.get(requirement.skillId) ?? []) {\n const entry = people.get(holder.employee.id) ?? {\n holder: holder.employee,\n matched: new Map<string, RoleMatchedSkill>(),\n };\n const current = entry.matched.get(requirement.skillId);\n const candidate: RoleMatchedSkill = {\n skillId: requirement.skillId,\n skillName: requirement.skillName,\n required: requirement.required,\n matchType: holder.matchType,\n viaSkill: holder.matchedSkill.name,\n proficiency: holder.proficiency,\n explanation: holder.explanation,\n };\n if (\n !current ||\n matchStrength(candidate.matchType) > matchStrength(current.matchType) ||\n (matchStrength(candidate.matchType) === matchStrength(current.matchType) &&\n (candidate.proficiency ?? -1) > (current.proficiency ?? -1))\n ) {\n entry.matched.set(requirement.skillId, candidate);\n }\n people.set(holder.employee.id, entry);\n }\n }\n\n const ranked: RoleMatch[] = [];\n for (const [employeeId, { holder, matched }] of people) {\n const matchedList = requirements\n .map((requirement) => matched.get(requirement.skillId))\n .filter((item): item is RoleMatchedSkill => item !== undefined);\n const coveredWeight = requirements\n .filter((requirement) => matched.has(requirement.skillId))\n .reduce((sum, requirement) => sum + weightOf(requirement), 0);\n ranked.push({\n employeeId,\n name: `${holder.firstName} ${holder.lastName}`.trim(),\n detail: [holder.position, holder.department].filter(Boolean).join(' · '),\n matchPercent: Math.round((coveredWeight / totalWeight) * 100),\n requiredCovered: matchedList.filter((item) => item.required).length,\n requiredTotal,\n matched: matchedList,\n missingRequired: requirements\n .filter((requirement) => requirement.required && !matched.has(requirement.skillId))\n .map((requirement) => requirement.skillName),\n });\n }\n return ranked.sort(compareMatches).slice(0, Math.max(0, limit));\n}\n\n/** Skills whose names, slugs or aliases contain the query (case-insensitive), best first. */\nexport function searchSkills<T extends { name: string; aliases: string[] }>(\n skills: readonly T[],\n query: string,\n limit = 8\n): T[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return [];\n const scored: { skill: T; score: number }[] = [];\n for (const skill of skills) {\n const name = skill.name.toLowerCase();\n let score = -1;\n if (name === needle) score = 0;\n else if (name.startsWith(needle)) score = 1;\n else if (skill.aliases.some((alias) => alias.toLowerCase() === needle)) score = 2;\n else if (name.includes(needle)) score = 3;\n else if (skill.aliases.some((alias) => alias.toLowerCase().includes(needle))) score = 4;\n if (score >= 0) scored.push({ skill, score });\n }\n return scored\n .sort((a, b) => a.score - b.score || a.skill.name.localeCompare(b.skill.name))\n .slice(0, limit)\n .map((entry) => entry.skill);\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executive dashboard (BOFF-4208). Workforce KPIs, attrition risk, headcount
|
|
3
|
+
* plan, skills shortages and payroll run-rate come from the server-side
|
|
4
|
+
* `crewExecutiveDashboard` rollup, so every figure is computed from the
|
|
5
|
+
* workspace's real rows by one deterministic implementation rather than
|
|
6
|
+
* re-derived in the browser. Project budget and department budget figures
|
|
7
|
+
* still come from the bootstrap store, which already owns those rows.
|
|
8
|
+
*/
|
|
1
9
|
export declare function DashboardExecutiveDashboardPage(): import("react").JSX.Element;
|
|
2
10
|
//# sourceMappingURL=DashboardExecutiveDashboardPage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardExecutiveDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DashboardExecutiveDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/DashboardExecutiveDashboardPage.tsx"],"names":[],"mappings":"AAudA;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,gCAiG9C"}
|