@forwardimpact/pathway 0.20.0 → 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.
- package/README.md +3 -3
- package/bin/fit-pathway.js +28 -28
- package/package.json +4 -4
- package/src/commands/agent.js +8 -8
- package/src/commands/build.js +7 -7
- package/src/commands/dev.js +7 -7
- package/src/commands/driver.js +1 -1
- package/src/commands/index.js +1 -1
- package/src/commands/init.js +1 -1
- package/src/commands/interview.js +8 -8
- package/src/commands/job.js +19 -19
- package/src/commands/level.js +60 -0
- package/src/commands/progress.js +20 -20
- package/src/commands/questions.js +3 -3
- package/src/commands/skill.js +1 -1
- package/src/commands/track.js +1 -1
- package/src/commands/update.js +12 -14
- package/src/components/action-buttons.js +3 -3
- package/src/components/builder.js +25 -25
- package/src/components/checklist.js +1 -1
- package/src/components/comparison-radar.js +3 -3
- package/src/components/detail.js +3 -3
- package/src/components/grid.js +1 -1
- package/src/components/radar-chart.js +3 -3
- package/src/components/skill-matrix.js +7 -7
- package/src/css/pages/landing.css +5 -5
- package/src/formatters/behaviour/dom.js +1 -1
- package/src/formatters/discipline/dom.js +1 -1
- package/src/formatters/driver/dom.js +1 -1
- package/src/formatters/index.js +5 -5
- package/src/formatters/interview/dom.js +1 -1
- package/src/formatters/interview/markdown.js +1 -1
- package/src/formatters/interview/shared.js +20 -20
- package/src/formatters/job/description.js +18 -18
- package/src/formatters/job/dom.js +12 -12
- package/src/formatters/job/markdown.js +7 -7
- package/src/formatters/json-ld.js +24 -24
- package/src/formatters/{grade → level}/dom.js +32 -28
- package/src/formatters/{grade → level}/markdown.js +20 -29
- package/src/formatters/{grade → level}/microdata.js +28 -38
- package/src/formatters/level/shared.js +86 -0
- package/src/formatters/progress/markdown.js +2 -2
- package/src/formatters/progress/shared.js +48 -48
- package/src/formatters/questions/markdown.js +8 -6
- package/src/formatters/questions/shared.js +7 -7
- package/src/formatters/skill/dom.js +4 -4
- package/src/formatters/skill/markdown.js +2 -2
- package/src/formatters/skill/microdata.js +3 -3
- package/src/formatters/skill/shared.js +3 -3
- package/src/formatters/track/dom.js +1 -1
- package/src/formatters/track/markdown.js +1 -1
- package/src/handout-main.js +13 -16
- package/src/handout.html +4 -4
- package/src/index.html +5 -5
- package/src/lib/card-mappers.js +17 -17
- package/src/lib/cli-command.js +3 -3
- package/src/lib/cli-output.js +2 -2
- package/src/lib/job-cache.js +11 -11
- package/src/lib/render.js +6 -6
- package/src/lib/state.js +2 -2
- package/src/lib/yaml-loader.js +9 -9
- package/src/main.js +10 -10
- package/src/pages/agent-builder.js +11 -11
- package/src/pages/assessment-results.js +27 -23
- package/src/pages/behaviour.js +1 -1
- package/src/pages/discipline.js +1 -1
- package/src/pages/driver.js +1 -1
- package/src/pages/interview-builder.js +6 -6
- package/src/pages/interview.js +9 -9
- package/src/pages/job-builder.js +6 -6
- package/src/pages/job.js +7 -7
- package/src/pages/landing.js +9 -9
- package/src/pages/level.js +122 -0
- package/src/pages/progress-builder.js +8 -8
- package/src/pages/progress.js +74 -74
- package/src/pages/self-assessment.js +8 -8
- package/src/pages/skill.js +1 -4
- package/src/pages/stage.js +1 -1
- package/src/pages/tool.js +1 -1
- package/src/pages/track.js +1 -1
- package/src/slide-main.js +22 -22
- package/src/slides/chapter.js +4 -4
- package/src/slides/index.js +11 -11
- package/src/slides/interview.js +2 -2
- package/src/slides/job.js +3 -3
- package/src/slides/level.js +32 -0
- package/src/slides/overview.js +9 -9
- package/src/slides/progress.js +13 -13
- package/src/slides.html +4 -4
- package/src/types.js +1 -1
- package/templates/install.template.sh +11 -8
- package/templates/job.template.md +2 -2
- package/src/commands/grade.js +0 -60
- package/src/formatters/grade/shared.js +0 -86
- package/src/pages/grade.js +0 -122
- package/src/slides/grade.js +0 -32
package/src/commands/progress.js
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
* Shows career progression analysis in the terminal.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* npx pathway progress <discipline> <
|
|
8
|
-
* npx pathway progress <discipline> <
|
|
9
|
-
* npx pathway progress <discipline> <
|
|
7
|
+
* npx pathway progress <discipline> <level> # Progress for trackless job
|
|
8
|
+
* npx pathway progress <discipline> <level> --track=<track> # Progress with track
|
|
9
|
+
* npx pathway progress <discipline> <from_level> --compare=<to_level> # Compare levels
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createCompositeCommand } from "./command-factory.js";
|
|
13
13
|
import {
|
|
14
14
|
prepareProgressDetail,
|
|
15
|
-
|
|
15
|
+
getDefaultTargetLevel,
|
|
16
16
|
} from "../formatters/progress/shared.js";
|
|
17
17
|
import { progressToMarkdown } from "../formatters/progress/markdown.js";
|
|
18
18
|
|
|
@@ -26,53 +26,53 @@ function formatProgress(view) {
|
|
|
26
26
|
|
|
27
27
|
export const runProgressCommand = createCompositeCommand({
|
|
28
28
|
commandName: "progress",
|
|
29
|
-
requiredArgs: ["discipline_id", "
|
|
29
|
+
requiredArgs: ["discipline_id", "level_id"],
|
|
30
30
|
findEntities: (data, args, options) => {
|
|
31
31
|
const discipline = data.disciplines.find((d) => d.id === args[0]);
|
|
32
|
-
const
|
|
32
|
+
const level = data.levels.find((g) => g.id === args[1]);
|
|
33
33
|
const track = options.track
|
|
34
34
|
? data.tracks.find((t) => t.id === options.track)
|
|
35
35
|
: null;
|
|
36
36
|
|
|
37
|
-
let
|
|
37
|
+
let targetLevel;
|
|
38
38
|
if (options.compare) {
|
|
39
|
-
|
|
40
|
-
if (!
|
|
41
|
-
console.error(`Target
|
|
39
|
+
targetLevel = data.levels.find((g) => g.id === options.compare);
|
|
40
|
+
if (!targetLevel) {
|
|
41
|
+
console.error(`Target level not found: ${options.compare}`);
|
|
42
42
|
process.exit(1);
|
|
43
43
|
}
|
|
44
44
|
} else {
|
|
45
|
-
|
|
46
|
-
if (!
|
|
47
|
-
console.error("No next
|
|
45
|
+
targetLevel = getDefaultTargetLevel(level, data.levels);
|
|
46
|
+
if (!targetLevel) {
|
|
47
|
+
console.error("No next level available for progression.");
|
|
48
48
|
process.exit(1);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
return { discipline,
|
|
52
|
+
return { discipline, level, track, targetLevel };
|
|
53
53
|
},
|
|
54
54
|
validateEntities: (entities, _data, options) => {
|
|
55
55
|
if (!entities.discipline) {
|
|
56
56
|
return `Discipline not found`;
|
|
57
57
|
}
|
|
58
|
-
if (!entities.
|
|
59
|
-
return `
|
|
58
|
+
if (!entities.level) {
|
|
59
|
+
return `Level not found`;
|
|
60
60
|
}
|
|
61
61
|
if (options.track && !entities.track) {
|
|
62
62
|
return `Track not found: ${options.track}`;
|
|
63
63
|
}
|
|
64
|
-
if (!entities.
|
|
65
|
-
return `Target
|
|
64
|
+
if (!entities.targetLevel) {
|
|
65
|
+
return `Target level not found`;
|
|
66
66
|
}
|
|
67
67
|
return null;
|
|
68
68
|
},
|
|
69
69
|
presenter: (entities, data) =>
|
|
70
70
|
prepareProgressDetail({
|
|
71
71
|
fromDiscipline: entities.discipline,
|
|
72
|
-
|
|
72
|
+
fromLevel: entities.level,
|
|
73
73
|
fromTrack: entities.track,
|
|
74
74
|
toDiscipline: entities.discipline,
|
|
75
|
-
|
|
75
|
+
toLevel: entities.targetLevel,
|
|
76
76
|
toTrack: entities.track,
|
|
77
77
|
skills: data.skills,
|
|
78
78
|
behaviours: data.behaviours,
|
|
@@ -49,7 +49,7 @@ function showQuestionsSummary(data) {
|
|
|
49
49
|
console.log(`\n❓ Questions\n`);
|
|
50
50
|
|
|
51
51
|
// Skill questions by level
|
|
52
|
-
const
|
|
52
|
+
const skillProficiencies = [
|
|
53
53
|
"awareness",
|
|
54
54
|
"foundational",
|
|
55
55
|
"working",
|
|
@@ -57,10 +57,10 @@ function showQuestionsSummary(data) {
|
|
|
57
57
|
"expert",
|
|
58
58
|
];
|
|
59
59
|
const roleTypes = ["professionalQuestions", "managementQuestions"];
|
|
60
|
-
const skillRows =
|
|
60
|
+
const skillRows = skillProficiencies.map((level) => {
|
|
61
61
|
let count = 0;
|
|
62
62
|
for (const skill of skills) {
|
|
63
|
-
const sq = questions.
|
|
63
|
+
const sq = questions.skillProficiencies?.[skill.id];
|
|
64
64
|
if (sq) {
|
|
65
65
|
for (const roleType of roleTypes) {
|
|
66
66
|
count += (sq[roleType]?.[level] || []).length;
|
package/src/commands/skill.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { createEntityCommand } from "./command-factory.js";
|
|
15
15
|
import { skillToMarkdown } from "../formatters/skill/markdown.js";
|
|
16
16
|
import { prepareSkillsList } from "../formatters/skill/shared.js";
|
|
17
|
-
import { getConceptEmoji } from "@forwardimpact/
|
|
17
|
+
import { getConceptEmoji } from "@forwardimpact/map/levels";
|
|
18
18
|
import { formatTable, formatError } from "../lib/cli-output.js";
|
|
19
19
|
import { generateSkillMarkdown } from "@forwardimpact/libpathway/agent";
|
|
20
20
|
import { formatAgentSkill } from "../formatters/agent/skill.js";
|
package/src/commands/track.js
CHANGED
|
@@ -14,7 +14,7 @@ import { createEntityCommand } from "./command-factory.js";
|
|
|
14
14
|
import { trackToMarkdown } from "../formatters/track/markdown.js";
|
|
15
15
|
import { sortTracksByName } from "../formatters/track/shared.js";
|
|
16
16
|
import { formatTable } from "../lib/cli-output.js";
|
|
17
|
-
import { getConceptEmoji } from "@forwardimpact/
|
|
17
|
+
import { getConceptEmoji } from "@forwardimpact/map/levels";
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Format track summary output
|
package/src/commands/update.js
CHANGED
|
@@ -3,20 +3,21 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Re-downloads the distribution bundle from the published site URL
|
|
5
5
|
* and updates the local ~/.fit/pathway/ installation.
|
|
6
|
+
* Updates the global @forwardimpact/pathway package if the version changed.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import { cp, mkdir, rm, readFile, writeFile, access } from "fs/promises";
|
|
9
10
|
import { join } from "path";
|
|
10
11
|
import { homedir } from "os";
|
|
11
12
|
import { execFileSync, execSync } from "child_process";
|
|
12
|
-
import { loadFrameworkConfig } from "@forwardimpact/
|
|
13
|
+
import { loadFrameworkConfig } from "@forwardimpact/map/loader";
|
|
13
14
|
|
|
14
15
|
const INSTALL_DIR = join(homedir(), ".fit", "pathway");
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Run the update command.
|
|
18
19
|
* Reads siteUrl from the installed framework.yaml, re-downloads the bundle,
|
|
19
|
-
* extracts data, and
|
|
20
|
+
* extracts data, and updates the global pathway package if the version changed.
|
|
20
21
|
*
|
|
21
22
|
* @param {Object} params - Command parameters
|
|
22
23
|
* @param {string} params.dataDir - Path to data directory (may be the installed one)
|
|
@@ -82,7 +83,7 @@ export async function runUpdateCommand({ dataDir: _dataDir, options }) {
|
|
|
82
83
|
]);
|
|
83
84
|
console.log(" ✓ Extracted");
|
|
84
85
|
|
|
85
|
-
// 3. Compare versions
|
|
86
|
+
// 3. Compare versions from bundle's package.json (version manifest)
|
|
86
87
|
const newPkgPath = join(extractDir, "package.json");
|
|
87
88
|
const oldPkgPath = join(INSTALL_DIR, "package.json");
|
|
88
89
|
const newPkg = JSON.parse(await readFile(newPkgPath, "utf8"));
|
|
@@ -104,21 +105,18 @@ export async function runUpdateCommand({ dataDir: _dataDir, options }) {
|
|
|
104
105
|
await cp(join(extractDir, "data"), installDataDir, { recursive: true });
|
|
105
106
|
console.log(" ✓ Data updated");
|
|
106
107
|
|
|
107
|
-
// 5. Update
|
|
108
|
+
// 5. Update version manifest
|
|
109
|
+
await writeFile(oldPkgPath, JSON.stringify(newPkg, null, 2) + "\n");
|
|
110
|
+
|
|
111
|
+
// 6. Update global pathway package if version changed
|
|
108
112
|
if (oldVersion !== newVersion) {
|
|
109
113
|
console.log(` Updating pathway ${oldVersion} → ${newVersion}...`);
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
execSync(`npm install -g @forwardimpact/pathway@${newVersion}`, {
|
|
115
|
+
stdio: "ignore",
|
|
116
|
+
});
|
|
117
|
+
console.log(" ✓ Global package updated");
|
|
112
118
|
}
|
|
113
119
|
|
|
114
|
-
// 6. Run npm install
|
|
115
|
-
console.log(" Installing dependencies...");
|
|
116
|
-
execSync("npm install --production --ignore-scripts --no-audit --no-fund", {
|
|
117
|
-
cwd: INSTALL_DIR,
|
|
118
|
-
stdio: "ignore",
|
|
119
|
-
});
|
|
120
|
-
console.log(" ✓ Dependencies installed");
|
|
121
|
-
|
|
122
120
|
// 7. Report
|
|
123
121
|
console.log(`
|
|
124
122
|
✅ Update complete!
|
|
@@ -30,7 +30,7 @@ export function createNavButton({ label, href, variant = "primary" }) {
|
|
|
30
30
|
/**
|
|
31
31
|
* Create a button to navigate to job builder with a parameter
|
|
32
32
|
* @param {Object} options - Configuration options
|
|
33
|
-
* @param {string} options.paramName - Parameter name (discipline,
|
|
33
|
+
* @param {string} options.paramName - Parameter name (discipline, level, track)
|
|
34
34
|
* @param {string} options.paramValue - Parameter value (the ID)
|
|
35
35
|
* @param {string} [options.label] - Optional custom label
|
|
36
36
|
* @returns {HTMLElement}
|
|
@@ -38,7 +38,7 @@ export function createNavButton({ label, href, variant = "primary" }) {
|
|
|
38
38
|
export function createJobBuilderButton({ paramName, paramValue, label }) {
|
|
39
39
|
const defaultLabels = {
|
|
40
40
|
discipline: "Build Job with this Discipline →",
|
|
41
|
-
|
|
41
|
+
level: "Build Job at this Level →",
|
|
42
42
|
track: "Build Job with this Track →",
|
|
43
43
|
};
|
|
44
44
|
|
|
@@ -52,7 +52,7 @@ export function createJobBuilderButton({ paramName, paramValue, label }) {
|
|
|
52
52
|
/**
|
|
53
53
|
* Create a button to navigate to interview prep with a parameter
|
|
54
54
|
* @param {Object} options - Configuration options
|
|
55
|
-
* @param {string} options.paramName - Parameter name (discipline,
|
|
55
|
+
* @param {string} options.paramName - Parameter name (discipline, level, track)
|
|
56
56
|
* @param {string} options.paramValue - Parameter value (the ID)
|
|
57
57
|
* @param {string} [options.label] - Optional custom label
|
|
58
58
|
* @returns {HTMLElement}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Builder component for discipline/
|
|
2
|
+
* Builder component for discipline/level/track selection pages
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import {
|
|
@@ -32,7 +32,7 @@ import { createReactive } from "../lib/reactive.js";
|
|
|
32
32
|
/**
|
|
33
33
|
* @typedef {Object} BuilderSelection
|
|
34
34
|
* @property {Object} discipline - Selected discipline
|
|
35
|
-
* @property {Object}
|
|
35
|
+
* @property {Object} level - Selected level
|
|
36
36
|
* @property {Object} track - Selected track
|
|
37
37
|
*/
|
|
38
38
|
|
|
@@ -78,10 +78,10 @@ export function createBuilder({
|
|
|
78
78
|
const selection = createReactive({
|
|
79
79
|
discipline: urlParams.get("discipline") || "",
|
|
80
80
|
track: urlParams.get("track") || "",
|
|
81
|
-
|
|
81
|
+
level: urlParams.get("level") || "",
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
const
|
|
84
|
+
const sortedLevels = [...data.levels].sort((a, b) => a.level - b.level);
|
|
85
85
|
|
|
86
86
|
// Create elements that need references
|
|
87
87
|
const previewContainer = div(
|
|
@@ -155,9 +155,9 @@ export function createBuilder({
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
// Subscribe to selection changes - all updates happen here
|
|
158
|
-
selection.subscribe(({ discipline, track,
|
|
159
|
-
// Track is now optional - only discipline and
|
|
160
|
-
if (!discipline || !
|
|
158
|
+
selection.subscribe(({ discipline, track, level }) => {
|
|
159
|
+
// Track is now optional - only discipline and level are required
|
|
160
|
+
if (!discipline || !level) {
|
|
161
161
|
previewContainer.innerHTML = "";
|
|
162
162
|
previewContainer.appendChild(
|
|
163
163
|
p({ className: "text-muted" }, emptyPreviewText),
|
|
@@ -168,9 +168,9 @@ export function createBuilder({
|
|
|
168
168
|
|
|
169
169
|
const disciplineObj = data.disciplines.find((d) => d.id === discipline);
|
|
170
170
|
const trackObj = track ? data.tracks.find((t) => t.id === track) : null;
|
|
171
|
-
const
|
|
171
|
+
const levelObj = data.levels.find((g) => g.id === level);
|
|
172
172
|
|
|
173
|
-
if (!disciplineObj || !
|
|
173
|
+
if (!disciplineObj || !levelObj) {
|
|
174
174
|
previewContainer.innerHTML = "";
|
|
175
175
|
previewContainer.appendChild(
|
|
176
176
|
p({ className: "text-muted" }, "Invalid selection. Please try again."),
|
|
@@ -182,7 +182,7 @@ export function createBuilder({
|
|
|
182
182
|
const selectionObj = {
|
|
183
183
|
discipline: disciplineObj,
|
|
184
184
|
track: trackObj,
|
|
185
|
-
|
|
185
|
+
level: levelObj,
|
|
186
186
|
};
|
|
187
187
|
const preview = previewPresenter(selectionObj, data);
|
|
188
188
|
|
|
@@ -193,8 +193,8 @@ export function createBuilder({
|
|
|
193
193
|
|
|
194
194
|
// Wire up button
|
|
195
195
|
actionButton.addEventListener("click", () => {
|
|
196
|
-
const { discipline, track,
|
|
197
|
-
window.location.hash = detailPath({ discipline, track,
|
|
196
|
+
const { discipline, track, level } = selection.get();
|
|
197
|
+
window.location.hash = detailPath({ discipline, track, level });
|
|
198
198
|
});
|
|
199
199
|
|
|
200
200
|
// Build the page
|
|
@@ -234,17 +234,17 @@ export function createBuilder({
|
|
|
234
234
|
getDisplayName: (d) => d.specialization || d.name,
|
|
235
235
|
}),
|
|
236
236
|
),
|
|
237
|
-
//
|
|
237
|
+
// Level selector (second)
|
|
238
238
|
div(
|
|
239
239
|
{ className: "form-group" },
|
|
240
|
-
label({ className: "form-label" }, labels.
|
|
240
|
+
label({ className: "form-label" }, labels.level || "Level"),
|
|
241
241
|
createSelectWithValue({
|
|
242
|
-
id: "
|
|
243
|
-
items:
|
|
244
|
-
initialValue: selection.get().
|
|
245
|
-
placeholder: "Select a
|
|
242
|
+
id: "level-select",
|
|
243
|
+
items: sortedLevels,
|
|
244
|
+
initialValue: selection.get().level,
|
|
245
|
+
placeholder: "Select a level...",
|
|
246
246
|
onChange: (value) => {
|
|
247
|
-
selection.update((prev) => ({ ...prev,
|
|
247
|
+
selection.update((prev) => ({ ...prev, level: value }));
|
|
248
248
|
},
|
|
249
249
|
getDisplayName: (g) => g.id,
|
|
250
250
|
}),
|
|
@@ -284,7 +284,7 @@ export function createBuilder({
|
|
|
284
284
|
|
|
285
285
|
// Trigger initial update if preselected
|
|
286
286
|
const initial = selection.get();
|
|
287
|
-
if (initial.discipline || initial.track || initial.
|
|
287
|
+
if (initial.discipline || initial.track || initial.level) {
|
|
288
288
|
setTimeout(() => selection.set(selection.get()), 0);
|
|
289
289
|
}
|
|
290
290
|
|
|
@@ -370,12 +370,12 @@ export function createProgressPreview(preview, selection) {
|
|
|
370
370
|
);
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
const { discipline,
|
|
373
|
+
const { discipline, level, track } = selection;
|
|
374
374
|
|
|
375
375
|
// Build badges array - track is optional
|
|
376
376
|
const badges = [
|
|
377
377
|
createBadge(discipline.specialization, "discipline"),
|
|
378
|
-
createBadge(
|
|
378
|
+
createBadge(level.id, "level"),
|
|
379
379
|
];
|
|
380
380
|
if (track) {
|
|
381
381
|
badges.push(createBadge(track.name, "track"));
|
|
@@ -394,19 +394,19 @@ export function createProgressPreview(preview, selection) {
|
|
|
394
394
|
div({ className: "preview-label" }, "Progression Paths Available"),
|
|
395
395
|
div(
|
|
396
396
|
{ className: "preview-paths" },
|
|
397
|
-
preview.
|
|
397
|
+
preview.nextLevel
|
|
398
398
|
? div(
|
|
399
399
|
{ className: "path-item" },
|
|
400
400
|
span({ className: "path-icon" }, "📈"),
|
|
401
401
|
span(
|
|
402
402
|
{},
|
|
403
|
-
`Next
|
|
403
|
+
`Next Level: ${preview.nextLevel.id} - ${preview.nextLevel.name}`,
|
|
404
404
|
),
|
|
405
405
|
)
|
|
406
406
|
: div(
|
|
407
407
|
{ className: "path-item text-muted" },
|
|
408
408
|
span({ className: "path-icon" }, "🏆"),
|
|
409
|
-
span({}, "You're at the highest
|
|
409
|
+
span({}, "You're at the highest level!"),
|
|
410
410
|
),
|
|
411
411
|
preview.validTracks.length > 0
|
|
412
412
|
? div(
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { div, span, details, summary } from "../lib/render.js";
|
|
9
|
-
import { getCapabilityEmoji } from "@forwardimpact/
|
|
9
|
+
import { getCapabilityEmoji } from "@forwardimpact/map/levels";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Create checklist display grouped by capability
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { ComparisonRadarChart } from "../lib/radar.js";
|
|
10
10
|
import { div, h3 } from "../lib/render.js";
|
|
11
11
|
import {
|
|
12
|
-
|
|
12
|
+
getSkillProficiencyIndex,
|
|
13
13
|
getBehaviourMaturityIndex,
|
|
14
14
|
formatLevel,
|
|
15
15
|
} from "../lib/render.js";
|
|
@@ -97,7 +97,7 @@ export function createComparisonSkillRadar(
|
|
|
97
97
|
|
|
98
98
|
currentData.push({
|
|
99
99
|
label: skillName,
|
|
100
|
-
value: currentSkill ?
|
|
100
|
+
value: currentSkill ? getSkillProficiencyIndex(currentSkill.level) : 0,
|
|
101
101
|
maxValue: 5,
|
|
102
102
|
description: currentSkill
|
|
103
103
|
? `${formatLevel(currentSkill.type)} - ${formatLevel(currentSkill.level)}`
|
|
@@ -106,7 +106,7 @@ export function createComparisonSkillRadar(
|
|
|
106
106
|
|
|
107
107
|
targetData.push({
|
|
108
108
|
label: skillName,
|
|
109
|
-
value: targetSkill ?
|
|
109
|
+
value: targetSkill ? getSkillProficiencyIndex(targetSkill.level) : 0,
|
|
110
110
|
maxValue: 5,
|
|
111
111
|
description: targetSkill
|
|
112
112
|
? `${formatLevel(targetSkill.type)} - ${formatLevel(targetSkill.level)}`
|
package/src/components/detail.js
CHANGED
|
@@ -21,9 +21,9 @@ import { createBackLink } from "./nav.js";
|
|
|
21
21
|
import { createTag } from "./card.js";
|
|
22
22
|
import { formatLevel } from "../lib/render.js";
|
|
23
23
|
import {
|
|
24
|
-
|
|
24
|
+
SKILL_PROFICIENCY_ORDER,
|
|
25
25
|
BEHAVIOUR_MATURITY_ORDER,
|
|
26
|
-
} from "@forwardimpact/
|
|
26
|
+
} from "@forwardimpact/map/levels";
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Create a detail page header
|
|
@@ -80,7 +80,7 @@ export function createDetailSection({ title, content }) {
|
|
|
80
80
|
*/
|
|
81
81
|
export function createLevelTable(descriptions, type = "skill") {
|
|
82
82
|
const levels =
|
|
83
|
-
type === "skill" ?
|
|
83
|
+
type === "skill" ? SKILL_PROFICIENCY_ORDER : BEHAVIOUR_MATURITY_ORDER;
|
|
84
84
|
|
|
85
85
|
const levelLabels = Object.fromEntries(
|
|
86
86
|
levels.map((level, index) => [level, String(index + 1)]),
|
package/src/components/grid.js
CHANGED
|
@@ -59,7 +59,7 @@ export function createFixedGrid(columns, children, options = {}) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
|
-
* Create a grid for form selectors (discipline/
|
|
62
|
+
* Create a grid for form selectors (discipline/level/track dropdowns)
|
|
63
63
|
* Uses auto-grid-sm (200px min)
|
|
64
64
|
* @param {HTMLElement[]} children - Form control elements
|
|
65
65
|
* @returns {HTMLElement}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { RadarChart } from "../lib/radar.js";
|
|
9
9
|
import { div, h3 } from "../lib/render.js";
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
getSkillProficiencyIndex,
|
|
12
12
|
getBehaviourMaturityIndex,
|
|
13
13
|
formatLevel,
|
|
14
14
|
} from "../lib/render.js";
|
|
@@ -33,9 +33,9 @@ export function createSkillRadar(skillMatrix, options = {}) {
|
|
|
33
33
|
|
|
34
34
|
const data = skillMatrix.map((skill) => ({
|
|
35
35
|
label: skill.skillName,
|
|
36
|
-
value:
|
|
36
|
+
value: getSkillProficiencyIndex(skill.proficiency),
|
|
37
37
|
maxValue: 5,
|
|
38
|
-
description: `${formatLevel(skill.type)} skill - ${formatLevel(skill.
|
|
38
|
+
description: `${formatLevel(skill.type)} skill - ${formatLevel(skill.proficiency)}`,
|
|
39
39
|
}));
|
|
40
40
|
|
|
41
41
|
const chart = new RadarChart({
|
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
td,
|
|
16
16
|
a,
|
|
17
17
|
} from "../lib/render.js";
|
|
18
|
-
import {
|
|
18
|
+
import { getSkillProficiencyIndex } from "../lib/render.js";
|
|
19
19
|
import { createLevelCell } from "./detail.js";
|
|
20
20
|
import { createBadge } from "./card.js";
|
|
21
|
-
import {
|
|
21
|
+
import { SKILL_PROFICIENCY_ORDER } from "@forwardimpact/map/levels";
|
|
22
22
|
import { truncate } from "../formatters/shared.js";
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -28,8 +28,8 @@ import { truncate } from "../formatters/shared.js";
|
|
|
28
28
|
*/
|
|
29
29
|
function sortByLevelDescending(skills) {
|
|
30
30
|
return [...skills].sort((a, b) => {
|
|
31
|
-
const levelA =
|
|
32
|
-
const levelB =
|
|
31
|
+
const levelA = SKILL_PROFICIENCY_ORDER.indexOf(a.level);
|
|
32
|
+
const levelB = SKILL_PROFICIENCY_ORDER.indexOf(b.level);
|
|
33
33
|
if (levelB !== levelA) {
|
|
34
34
|
return levelB - levelA;
|
|
35
35
|
}
|
|
@@ -50,7 +50,7 @@ export function createSkillMatrix(skillMatrix) {
|
|
|
50
50
|
const sortedSkills = sortByLevelDescending(skillMatrix);
|
|
51
51
|
|
|
52
52
|
const rows = sortedSkills.map((skill) => {
|
|
53
|
-
const levelIndex =
|
|
53
|
+
const levelIndex = getSkillProficiencyIndex(skill.proficiency);
|
|
54
54
|
|
|
55
55
|
return tr(
|
|
56
56
|
{ className: skill.isHumanOnly ? "human-only-row" : "" },
|
|
@@ -69,10 +69,10 @@ export function createSkillMatrix(skillMatrix) {
|
|
|
69
69
|
: null,
|
|
70
70
|
),
|
|
71
71
|
td({}, createBadge(skill.capability, skill.capability)),
|
|
72
|
-
createLevelCell(levelIndex, 5, skill.
|
|
72
|
+
createLevelCell(levelIndex, 5, skill.proficiency),
|
|
73
73
|
td(
|
|
74
74
|
{ className: "skill-description" },
|
|
75
|
-
truncate(skill.
|
|
75
|
+
truncate(skill.proficiencyDescription, 80),
|
|
76
76
|
),
|
|
77
77
|
);
|
|
78
78
|
});
|
|
@@ -63,20 +63,20 @@
|
|
|
63
63
|
margin: 0;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
/*
|
|
67
|
-
.
|
|
66
|
+
/* Levels timeline */
|
|
67
|
+
.levels-timeline {
|
|
68
68
|
display: flex;
|
|
69
69
|
flex-direction: column;
|
|
70
70
|
gap: var(--space-md);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
.
|
|
73
|
+
.level-timeline-item {
|
|
74
74
|
display: flex;
|
|
75
75
|
gap: var(--space-lg);
|
|
76
76
|
align-items: flex-start;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
.
|
|
79
|
+
.level-level-marker {
|
|
80
80
|
width: 50px;
|
|
81
81
|
height: 50px;
|
|
82
82
|
border-radius: 50%;
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
flex-shrink: 0;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
.
|
|
93
|
+
.level-timeline-content {
|
|
94
94
|
flex: 1;
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -21,7 +21,7 @@ import { createLevelCell } from "../../components/detail.js";
|
|
|
21
21
|
import {
|
|
22
22
|
BEHAVIOUR_MATURITY_ORDER,
|
|
23
23
|
getConceptEmoji,
|
|
24
|
-
} from "@forwardimpact/
|
|
24
|
+
} from "@forwardimpact/map/levels";
|
|
25
25
|
import { prepareBehaviourDetail } from "./shared.js";
|
|
26
26
|
import { createJsonLdScript, behaviourToJsonLd } from "../json-ld.js";
|
|
27
27
|
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
createJobBuilderButton,
|
|
19
19
|
createInterviewPrepButton,
|
|
20
20
|
} from "../../components/action-buttons.js";
|
|
21
|
-
import { getConceptEmoji } from "@forwardimpact/
|
|
21
|
+
import { getConceptEmoji } from "@forwardimpact/map/levels";
|
|
22
22
|
import { prepareDisciplineDetail } from "./shared.js";
|
|
23
23
|
import { createJsonLdScript, disciplineToJsonLd } from "../json-ld.js";
|
|
24
24
|
import { createBadge } from "../../components/card.js";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { div, heading1, heading2, p, a, span } from "../../lib/render.js";
|
|
6
6
|
import { createBackLink } from "../../components/nav.js";
|
|
7
7
|
import { prepareDriverDetail } from "./shared.js";
|
|
8
|
-
import { getConceptEmoji } from "@forwardimpact/
|
|
8
|
+
import { getConceptEmoji } from "@forwardimpact/map/levels";
|
|
9
9
|
import { createJsonLdScript, driverToJsonLd } from "../json-ld.js";
|
|
10
10
|
|
|
11
11
|
/**
|
package/src/formatters/index.js
CHANGED
|
@@ -55,10 +55,10 @@ export {
|
|
|
55
55
|
disciplineToMicrodata,
|
|
56
56
|
} from "./discipline/microdata.js";
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
export {
|
|
60
|
-
export {
|
|
61
|
-
export {
|
|
58
|
+
// Level formatters
|
|
59
|
+
export { levelListToMarkdown, levelToMarkdown } from "./level/markdown.js";
|
|
60
|
+
export { levelToDOM } from "./level/dom.js";
|
|
61
|
+
export { levelListToMicrodata, levelToMicrodata } from "./level/microdata.js";
|
|
62
62
|
|
|
63
63
|
// Track formatters
|
|
64
64
|
export { trackListToMarkdown, trackToMarkdown } from "./track/markdown.js";
|
|
@@ -75,7 +75,7 @@ export {
|
|
|
75
75
|
behaviourToJsonLd,
|
|
76
76
|
disciplineToJsonLd,
|
|
77
77
|
trackToJsonLd,
|
|
78
|
-
|
|
78
|
+
levelToJsonLd,
|
|
79
79
|
driverToJsonLd,
|
|
80
80
|
stageToJsonLd,
|
|
81
81
|
} from "./json-ld.js";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { div, heading1, heading2, p, span } from "../../lib/render.js";
|
|
6
6
|
import { createBackLink } from "../../components/nav.js";
|
|
7
7
|
import { createLevelDots } from "../../components/detail.js";
|
|
8
|
-
import { getConceptEmoji } from "@forwardimpact/
|
|
8
|
+
import { getConceptEmoji } from "@forwardimpact/map/levels";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Format interview detail as DOM elements
|