placementt-core 1.400.968 → 1.400.970
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/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/skillsResolver.d.ts +41 -0
- package/lib/skillsResolver.js +47 -0
- package/lib/skillsResolver.js.map +1 -0
- package/lib/typeDefinitions.d.ts +36 -2
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/skillsResolver.ts +73 -0
- package/src/typeDefinitions.ts +34 -3
package/lib/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from "./customerCareConfig";
|
|
|
7
7
|
export * from "./firebase/firebaseConfig";
|
|
8
8
|
export * from "./firebase/firebaseQuery";
|
|
9
9
|
export * from "./typeDefinitions";
|
|
10
|
+
export * from "./skillsResolver";
|
|
10
11
|
export * from "./emailSections";
|
|
11
12
|
export * from "./exportTransformers";
|
|
12
13
|
export * from "./compassExport";
|
package/lib/index.js
CHANGED
|
@@ -27,6 +27,7 @@ __exportStar(require("./customerCareConfig"), exports);
|
|
|
27
27
|
__exportStar(require("./firebase/firebaseConfig"), exports);
|
|
28
28
|
__exportStar(require("./firebase/firebaseQuery"), exports);
|
|
29
29
|
__exportStar(require("./typeDefinitions"), exports);
|
|
30
|
+
__exportStar(require("./skillsResolver"), exports);
|
|
30
31
|
__exportStar(require("./emailSections"), exports);
|
|
31
32
|
__exportStar(require("./exportTransformers"), exports);
|
|
32
33
|
__exportStar(require("./compassExport"), exports);
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,sDAAoC;AACpC,gEAA8C;AAC9C,0DAAwC;AACxC,2DAAyC;AACzC,kDAAgC;AAChC,uDAAqC;AACrC,4DAA0C;AAC1C,2DAAyC;AAEzC,oDAAkC;AAClC,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,2DAAyC;AACzC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,0CAAwB;AACxB,yCAAuB;AACvB,4DAA0C;AAC1C,kDAAgC;AAChC,iDAA+B;AAC/B,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAiD;AACjD,yEAAuD;AACvD,kEAAgD;AAChD,kEAAgD;AAChD,oEAAkD;AAClD,yGAAuF;AACvF,0GAAwF;AACxF,+FAA6E;AAC7E,4DAA0C;AAC1C,oEAAkD;AAClD,gEAA8C;AAC9C,2EAAyD;AACzD,6CAA2B;AAC3B,+CAA6B;AAC7B,6DAAuE;AAA9D,2IAAA,OAAO,OAAuB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,sDAAoC;AACpC,gEAA8C;AAC9C,0DAAwC;AACxC,2DAAyC;AACzC,kDAAgC;AAChC,uDAAqC;AACrC,4DAA0C;AAC1C,2DAAyC;AAEzC,oDAAkC;AAClC,mDAAiC;AACjC,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,2DAAyC;AACzC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,0CAAwB;AACxB,yCAAuB;AACvB,4DAA0C;AAC1C,kDAAgC;AAChC,iDAA+B;AAC/B,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAiD;AACjD,yEAAuD;AACvD,kEAAgD;AAChD,kEAAgD;AAChD,oEAAkD;AAClD,yGAAuF;AACvF,0GAAwF;AACxF,+FAA6E;AAC7E,4DAA0C;AAC1C,oEAAkD;AAClD,gEAA8C;AAC9C,2EAAyD;AACzD,6CAA2B;AAC3B,+CAA6B;AAC7B,6DAAuE;AAA9D,2IAAA,OAAO,OAAuB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { InstituteData, SkillLabel, SkillsMapping } from "./typeDefinitions";
|
|
2
|
+
/**
|
|
3
|
+
* Shared resolution of which skills an institute — and a specific student — should see.
|
|
4
|
+
* Used by the web app (assessment forms, setup, analytics) and the backend (external
|
|
5
|
+
* parent/employer assessment forms), so keep it dependency-free.
|
|
6
|
+
*
|
|
7
|
+
* Model:
|
|
8
|
+
* - Institute base set: labels tagged with the institute's skillsFramework, or the
|
|
9
|
+
* stored `skills` id list when the framework is "custom".
|
|
10
|
+
* - Per-student set: staff-defined skillsMappings rules are evaluated against the
|
|
11
|
+
* student's detail fields at view time. Matching rules contribute the union of
|
|
12
|
+
* their skills; a student matching no rule gets the full base set.
|
|
13
|
+
*/
|
|
14
|
+
type InstituteSkillsConfig = Pick<InstituteData, "skillsFramework" | "skillsMappings"> & {
|
|
15
|
+
skills?: string[];
|
|
16
|
+
};
|
|
17
|
+
/** Ids of the institute's base skill set (no student context). */
|
|
18
|
+
export declare function resolveInstituteSkillIds(institute: InstituteSkillsConfig, allLabels: {
|
|
19
|
+
[id: string]: SkillLabel;
|
|
20
|
+
}): string[];
|
|
21
|
+
/** Does this student's detail fields satisfy a mapping's filters?
|
|
22
|
+
* Fields are ANDed; values within a field are ORed. An empty rule matches nobody. */
|
|
23
|
+
export declare function studentMatchesSkillsMapping(studentDetails: {
|
|
24
|
+
[field: string]: unknown;
|
|
25
|
+
} | undefined, filters: SkillsMapping["filters"]): boolean;
|
|
26
|
+
/** Ids of the skills this specific student should be served.
|
|
27
|
+
* No mappings configured (or no student context) → full base set. */
|
|
28
|
+
export declare function resolveStudentSkillIds(institute: InstituteSkillsConfig, allLabels: {
|
|
29
|
+
[id: string]: SkillLabel;
|
|
30
|
+
}, studentDetails?: {
|
|
31
|
+
[field: string]: unknown;
|
|
32
|
+
}): string[];
|
|
33
|
+
/** Convenience: same as resolveStudentSkillIds but returns the label objects keyed by id. */
|
|
34
|
+
export declare function resolveStudentSkills(institute: InstituteSkillsConfig, allLabels: {
|
|
35
|
+
[id: string]: SkillLabel;
|
|
36
|
+
}, studentDetails?: {
|
|
37
|
+
[field: string]: unknown;
|
|
38
|
+
}): {
|
|
39
|
+
[id: string]: SkillLabel;
|
|
40
|
+
};
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveInstituteSkillIds = resolveInstituteSkillIds;
|
|
4
|
+
exports.studentMatchesSkillsMapping = studentMatchesSkillsMapping;
|
|
5
|
+
exports.resolveStudentSkillIds = resolveStudentSkillIds;
|
|
6
|
+
exports.resolveStudentSkills = resolveStudentSkills;
|
|
7
|
+
/** Ids of the institute's base skill set (no student context). */
|
|
8
|
+
function resolveInstituteSkillIds(institute, allLabels) {
|
|
9
|
+
const framework = institute.skillsFramework;
|
|
10
|
+
if (framework && framework !== "custom") {
|
|
11
|
+
return Object.entries(allLabels)
|
|
12
|
+
.filter(([, label]) => label.framework === framework)
|
|
13
|
+
.map(([id]) => id);
|
|
14
|
+
}
|
|
15
|
+
return (institute.skills || []).filter((id) => allLabels[id]);
|
|
16
|
+
}
|
|
17
|
+
/** Does this student's detail fields satisfy a mapping's filters?
|
|
18
|
+
* Fields are ANDed; values within a field are ORed. An empty rule matches nobody. */
|
|
19
|
+
function studentMatchesSkillsMapping(studentDetails, filters) {
|
|
20
|
+
const entries = Object.entries(filters || {}).filter(([, values]) => values?.length);
|
|
21
|
+
if (entries.length === 0)
|
|
22
|
+
return false;
|
|
23
|
+
return entries.every(([field, values]) => {
|
|
24
|
+
const studentValue = String(studentDetails?.[field] ?? "").trim().toLowerCase();
|
|
25
|
+
return values.some((v) => String(v).trim().toLowerCase() === studentValue);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Ids of the skills this specific student should be served.
|
|
29
|
+
* No mappings configured (or no student context) → full base set. */
|
|
30
|
+
function resolveStudentSkillIds(institute, allLabels, studentDetails) {
|
|
31
|
+
const base = resolveInstituteSkillIds(institute, allLabels);
|
|
32
|
+
const mappings = institute.skillsMappings || [];
|
|
33
|
+
if (!studentDetails || mappings.length === 0)
|
|
34
|
+
return base;
|
|
35
|
+
const matched = mappings.filter((m) => studentMatchesSkillsMapping(studentDetails, m.filters));
|
|
36
|
+
if (matched.length === 0)
|
|
37
|
+
return base;
|
|
38
|
+
const ids = Array.from(new Set(matched.flatMap((m) => m.skills)))
|
|
39
|
+
.filter((id) => allLabels[id] && base.includes(id));
|
|
40
|
+
return ids.length ? ids : base;
|
|
41
|
+
}
|
|
42
|
+
/** Convenience: same as resolveStudentSkillIds but returns the label objects keyed by id. */
|
|
43
|
+
function resolveStudentSkills(institute, allLabels, studentDetails) {
|
|
44
|
+
return Object.fromEntries(resolveStudentSkillIds(institute, allLabels, studentDetails)
|
|
45
|
+
.map((id) => [id, allLabels[id]]));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=skillsResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillsResolver.js","sourceRoot":"","sources":["../src/skillsResolver.ts"],"names":[],"mappings":";;AAkBA,4DAWC;AAID,kEAUC;AAID,wDAeC;AAGD,oDAOC;AAvDD,kEAAkE;AAClE,SAAgB,wBAAwB,CACpC,SAAgC,EAChC,SAAqC;IAErC,MAAM,SAAS,GAAG,SAAS,CAAC,eAAe,CAAC;IAC5C,IAAI,SAAS,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;aAC3B,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC;aACpD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;qFACqF;AACrF,SAAgB,2BAA2B,CACvC,cAAsD,EACtD,OAAiC;IAEjC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE;QACrC,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAChF,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;AACP,CAAC;AAED;qEACqE;AACrE,SAAgB,sBAAsB,CAClC,SAAgC,EAChC,SAAqC,EACrC,cAA2C;IAE3C,MAAM,IAAI,GAAG,wBAAwB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,SAAS,CAAC,cAAc,IAAI,EAAE,CAAC;IAChD,IAAI,CAAC,cAAc,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1D,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,2BAA2B,CAAC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/F,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;SAC5D,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IACxD,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,CAAC;AAED,6FAA6F;AAC7F,SAAgB,oBAAoB,CAChC,SAAgC,EAChC,SAAqC,EACrC,cAA2C;IAE3C,OAAO,MAAM,CAAC,WAAW,CAAC,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC;SACjF,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3C,CAAC"}
|
package/lib/typeDefinitions.d.ts
CHANGED
|
@@ -931,8 +931,16 @@ export type InstituteData = {
|
|
|
931
931
|
};
|
|
932
932
|
skillsAssessments?: boolean;
|
|
933
933
|
assessActivitySkills?: boolean;
|
|
934
|
+
/** The framework the institute assesses. When "skillsBuilder"/"sdsMetaskills", the
|
|
935
|
+
* skill set is resolved dynamically from skillsLabels tagged with that framework —
|
|
936
|
+
* NOT from a stored id list. When "custom", `skills` holds the selected label ids. */
|
|
934
937
|
skillsFramework?: SkillsFrameworkKey;
|
|
938
|
+
/** Only meaningful when skillsFramework is "custom": the selected skillsLabels ids
|
|
939
|
+
* (generic public labels and/or the school's own custom labels). */
|
|
935
940
|
skills: string[];
|
|
941
|
+
/** Staff-defined rules serving specific skills to specific students based on their
|
|
942
|
+
* detail fields (studentsFields). Evaluated at assessment view time. */
|
|
943
|
+
skillsMappings?: SkillsMapping[];
|
|
936
944
|
scheduledSkillsAssessments?: {
|
|
937
945
|
[key in "yearStart" | "yearEnd" | "eachTerm" | "preWorkExperience" | "postWorkExperience" | "employerInteraction"]?: {
|
|
938
946
|
students?: boolean;
|
|
@@ -2852,7 +2860,7 @@ export type EmailInteraction = {
|
|
|
2852
2860
|
* must NOT set this, or it would escalate recursively. */
|
|
2853
2861
|
fallback?: ReminderFallbackType;
|
|
2854
2862
|
};
|
|
2855
|
-
/** Skills framework a skill can be tagged against. "custom" is the
|
|
2863
|
+
/** Skills framework a skill can be tagged against. "custom" is the school's own selection
|
|
2856
2864
|
* and is never used as a tag on a SkillLabel. */
|
|
2857
2865
|
export type SkillsFrameworkKey = "custom" | "skillsBuilder" | "sdsMetaskills";
|
|
2858
2866
|
export type SkillLabel = {
|
|
@@ -2860,7 +2868,29 @@ export type SkillLabel = {
|
|
|
2860
2868
|
description: string;
|
|
2861
2869
|
category: keyof typeof skillLabelColours;
|
|
2862
2870
|
public: boolean;
|
|
2863
|
-
frameworks
|
|
2871
|
+
/** The single framework this label belongs to. Skills on different frameworks are
|
|
2872
|
+
* completely separate documents — duplicates across frameworks are intentional.
|
|
2873
|
+
* Absent for generic/custom labels. */
|
|
2874
|
+
framework?: SkillsFrameworkKey;
|
|
2875
|
+
/** Set when a school created this label as a custom skill (scoped to that school).
|
|
2876
|
+
* Absent for platform-wide labels. */
|
|
2877
|
+
oId?: string;
|
|
2878
|
+
};
|
|
2879
|
+
/**
|
|
2880
|
+
* A staff-defined rule mapping students to the skills they are served on assessments.
|
|
2881
|
+
* `filters` keys are student detail field names (from InstituteData.studentsFields);
|
|
2882
|
+
* values are the accepted values for that field. A student matches a rule when EVERY
|
|
2883
|
+
* filtered field's value is one of the accepted values (values within a field are OR,
|
|
2884
|
+
* fields are AND). A student matching multiple rules is served the UNION of their
|
|
2885
|
+
* skills. A student matching no rule falls back to the institute's full base set.
|
|
2886
|
+
*/
|
|
2887
|
+
export type SkillsMapping = {
|
|
2888
|
+
id: string;
|
|
2889
|
+
name?: string;
|
|
2890
|
+
filters: {
|
|
2891
|
+
[field: string]: string[];
|
|
2892
|
+
};
|
|
2893
|
+
skills: string[];
|
|
2864
2894
|
};
|
|
2865
2895
|
/** Rater types for skills assessments (mirrors SkillAssessment.userType). */
|
|
2866
2896
|
export type SkillRater = "students" | "parents" | "employers";
|
|
@@ -3479,5 +3509,9 @@ export type LmiStandardsMatchReview = {
|
|
|
3479
3509
|
standardLevel: number;
|
|
3480
3510
|
confidence: number;
|
|
3481
3511
|
}[];
|
|
3512
|
+
/** Why-it-did-what-it-did counters + samples, for debugging the run. */
|
|
3513
|
+
diagnostics?: {
|
|
3514
|
+
[key: string]: unknown;
|
|
3515
|
+
};
|
|
3482
3516
|
};
|
|
3483
3517
|
export {};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./firebase/firebaseConfig";
|
|
|
9
9
|
export * from "./firebase/firebaseQuery";
|
|
10
10
|
|
|
11
11
|
export * from "./typeDefinitions";
|
|
12
|
+
export * from "./skillsResolver";
|
|
12
13
|
export * from "./emailSections";
|
|
13
14
|
export * from "./exportTransformers";
|
|
14
15
|
export * from "./compassExport";
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {InstituteData, SkillLabel, SkillsMapping} from "./typeDefinitions";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared resolution of which skills an institute — and a specific student — should see.
|
|
5
|
+
* Used by the web app (assessment forms, setup, analytics) and the backend (external
|
|
6
|
+
* parent/employer assessment forms), so keep it dependency-free.
|
|
7
|
+
*
|
|
8
|
+
* Model:
|
|
9
|
+
* - Institute base set: labels tagged with the institute's skillsFramework, or the
|
|
10
|
+
* stored `skills` id list when the framework is "custom".
|
|
11
|
+
* - Per-student set: staff-defined skillsMappings rules are evaluated against the
|
|
12
|
+
* student's detail fields at view time. Matching rules contribute the union of
|
|
13
|
+
* their skills; a student matching no rule gets the full base set.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
type InstituteSkillsConfig = Pick<InstituteData, "skillsFramework" | "skillsMappings"> & {skills?: string[]};
|
|
17
|
+
|
|
18
|
+
/** Ids of the institute's base skill set (no student context). */
|
|
19
|
+
export function resolveInstituteSkillIds(
|
|
20
|
+
institute: InstituteSkillsConfig,
|
|
21
|
+
allLabels: {[id: string]: SkillLabel},
|
|
22
|
+
): string[] {
|
|
23
|
+
const framework = institute.skillsFramework;
|
|
24
|
+
if (framework && framework !== "custom") {
|
|
25
|
+
return Object.entries(allLabels)
|
|
26
|
+
.filter(([, label]) => label.framework === framework)
|
|
27
|
+
.map(([id]) => id);
|
|
28
|
+
}
|
|
29
|
+
return (institute.skills || []).filter((id) => allLabels[id]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Does this student's detail fields satisfy a mapping's filters?
|
|
33
|
+
* Fields are ANDed; values within a field are ORed. An empty rule matches nobody. */
|
|
34
|
+
export function studentMatchesSkillsMapping(
|
|
35
|
+
studentDetails: {[field: string]: unknown} | undefined,
|
|
36
|
+
filters: SkillsMapping["filters"],
|
|
37
|
+
): boolean {
|
|
38
|
+
const entries = Object.entries(filters || {}).filter(([, values]) => values?.length);
|
|
39
|
+
if (entries.length === 0) return false;
|
|
40
|
+
return entries.every(([field, values]) => {
|
|
41
|
+
const studentValue = String(studentDetails?.[field] ?? "").trim().toLowerCase();
|
|
42
|
+
return values.some((v) => String(v).trim().toLowerCase() === studentValue);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Ids of the skills this specific student should be served.
|
|
47
|
+
* No mappings configured (or no student context) → full base set. */
|
|
48
|
+
export function resolveStudentSkillIds(
|
|
49
|
+
institute: InstituteSkillsConfig,
|
|
50
|
+
allLabels: {[id: string]: SkillLabel},
|
|
51
|
+
studentDetails?: {[field: string]: unknown},
|
|
52
|
+
): string[] {
|
|
53
|
+
const base = resolveInstituteSkillIds(institute, allLabels);
|
|
54
|
+
const mappings = institute.skillsMappings || [];
|
|
55
|
+
if (!studentDetails || mappings.length === 0) return base;
|
|
56
|
+
|
|
57
|
+
const matched = mappings.filter((m) => studentMatchesSkillsMapping(studentDetails, m.filters));
|
|
58
|
+
if (matched.length === 0) return base;
|
|
59
|
+
|
|
60
|
+
const ids = Array.from(new Set(matched.flatMap((m) => m.skills)))
|
|
61
|
+
.filter((id) => allLabels[id] && base.includes(id));
|
|
62
|
+
return ids.length ? ids : base;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Convenience: same as resolveStudentSkillIds but returns the label objects keyed by id. */
|
|
66
|
+
export function resolveStudentSkills(
|
|
67
|
+
institute: InstituteSkillsConfig,
|
|
68
|
+
allLabels: {[id: string]: SkillLabel},
|
|
69
|
+
studentDetails?: {[field: string]: unknown},
|
|
70
|
+
): {[id: string]: SkillLabel} {
|
|
71
|
+
return Object.fromEntries(resolveStudentSkillIds(institute, allLabels, studentDetails)
|
|
72
|
+
.map((id) => [id, allLabels[id]]));
|
|
73
|
+
}
|
package/src/typeDefinitions.ts
CHANGED
|
@@ -940,8 +940,16 @@ export type InstituteData = {
|
|
|
940
940
|
// SKILLS ASSESSMENT CONFIGURATION
|
|
941
941
|
skillsAssessments?: boolean,
|
|
942
942
|
assessActivitySkills?: boolean, // ask students to self-assess skills when logging an extracurricular activity
|
|
943
|
-
|
|
943
|
+
/** The framework the institute assesses. When "skillsBuilder"/"sdsMetaskills", the
|
|
944
|
+
* skill set is resolved dynamically from skillsLabels tagged with that framework —
|
|
945
|
+
* NOT from a stored id list. When "custom", `skills` holds the selected label ids. */
|
|
946
|
+
skillsFramework?: SkillsFrameworkKey,
|
|
947
|
+
/** Only meaningful when skillsFramework is "custom": the selected skillsLabels ids
|
|
948
|
+
* (generic public labels and/or the school's own custom labels). */
|
|
944
949
|
skills: string[]
|
|
950
|
+
/** Staff-defined rules serving specific skills to specific students based on their
|
|
951
|
+
* detail fields (studentsFields). Evaluated at assessment view time. */
|
|
952
|
+
skillsMappings?: SkillsMapping[],
|
|
945
953
|
scheduledSkillsAssessments?: {
|
|
946
954
|
[key in "yearStart" | "yearEnd" | "eachTerm" | "preWorkExperience" | "postWorkExperience" | "employerInteraction"]?: {
|
|
947
955
|
students?: boolean,
|
|
@@ -2771,7 +2779,7 @@ export type EmailInteraction = {
|
|
|
2771
2779
|
fallback?: ReminderFallbackType,
|
|
2772
2780
|
}
|
|
2773
2781
|
|
|
2774
|
-
/** Skills framework a skill can be tagged against. "custom" is the
|
|
2782
|
+
/** Skills framework a skill can be tagged against. "custom" is the school's own selection
|
|
2775
2783
|
* and is never used as a tag on a SkillLabel. */
|
|
2776
2784
|
export type SkillsFrameworkKey = "custom" | "skillsBuilder" | "sdsMetaskills";
|
|
2777
2785
|
|
|
@@ -2780,7 +2788,28 @@ export type SkillLabel = {
|
|
|
2780
2788
|
description: string,
|
|
2781
2789
|
category: keyof typeof skillLabelColours,
|
|
2782
2790
|
public: boolean,
|
|
2783
|
-
|
|
2791
|
+
/** The single framework this label belongs to. Skills on different frameworks are
|
|
2792
|
+
* completely separate documents — duplicates across frameworks are intentional.
|
|
2793
|
+
* Absent for generic/custom labels. */
|
|
2794
|
+
framework?: SkillsFrameworkKey,
|
|
2795
|
+
/** Set when a school created this label as a custom skill (scoped to that school).
|
|
2796
|
+
* Absent for platform-wide labels. */
|
|
2797
|
+
oId?: string,
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
/**
|
|
2801
|
+
* A staff-defined rule mapping students to the skills they are served on assessments.
|
|
2802
|
+
* `filters` keys are student detail field names (from InstituteData.studentsFields);
|
|
2803
|
+
* values are the accepted values for that field. A student matches a rule when EVERY
|
|
2804
|
+
* filtered field's value is one of the accepted values (values within a field are OR,
|
|
2805
|
+
* fields are AND). A student matching multiple rules is served the UNION of their
|
|
2806
|
+
* skills. A student matching no rule falls back to the institute's full base set.
|
|
2807
|
+
*/
|
|
2808
|
+
export type SkillsMapping = {
|
|
2809
|
+
id: string,
|
|
2810
|
+
name?: string,
|
|
2811
|
+
filters: {[field: string]: string[]},
|
|
2812
|
+
skills: string[],
|
|
2784
2813
|
}
|
|
2785
2814
|
|
|
2786
2815
|
/** Rater types for skills assessments (mirrors SkillAssessment.userType). */
|
|
@@ -3447,4 +3476,6 @@ export type LmiStandardsMatchReview = {
|
|
|
3447
3476
|
standardLevel: number,
|
|
3448
3477
|
confidence: number, // 0-1 heuristic score
|
|
3449
3478
|
}[],
|
|
3479
|
+
/** Why-it-did-what-it-did counters + samples, for debugging the run. */
|
|
3480
|
+
diagnostics?: {[key: string]: unknown},
|
|
3450
3481
|
}
|