@magmamath/students-features 1.2.1-rc.31 → 1.2.1-rc.32
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/commonjs/features/pmProgress/model/PmTreeModel.js +4 -2
- package/dist/commonjs/features/pmProgress/model/PmTreeModel.js.map +1 -1
- package/dist/commonjs/features/pmProgress/shared/TreeNormalizer.js +52 -0
- package/dist/commonjs/features/pmProgress/shared/TreeNormalizer.js.map +1 -0
- package/dist/module/features/pmProgress/model/PmTreeModel.js +4 -2
- package/dist/module/features/pmProgress/model/PmTreeModel.js.map +1 -1
- package/dist/module/features/pmProgress/shared/TreeNormalizer.js +47 -0
- package/dist/module/features/pmProgress/shared/TreeNormalizer.js.map +1 -0
- package/dist/typescript/commonjs/features/pmProgress/model/PmTreeModel.d.ts +1 -1
- package/dist/typescript/commonjs/features/pmProgress/model/PmTreeModel.d.ts.map +1 -1
- package/dist/typescript/commonjs/features/pmProgress/shared/TreeNormalizer.d.ts +17 -0
- package/dist/typescript/commonjs/features/pmProgress/shared/TreeNormalizer.d.ts.map +1 -0
- package/dist/typescript/module/features/pmProgress/model/PmTreeModel.d.ts +1 -1
- package/dist/typescript/module/features/pmProgress/model/PmTreeModel.d.ts.map +1 -1
- package/dist/typescript/module/features/pmProgress/shared/TreeNormalizer.d.ts +17 -0
- package/dist/typescript/module/features/pmProgress/shared/TreeNormalizer.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/features/pmProgress/model/PmTreeModel.ts +4 -2
- package/src/features/pmProgress/shared/TreeNormalizer.ts +64 -0
|
@@ -8,6 +8,7 @@ var _effector = require("effector");
|
|
|
8
8
|
var _effectorAction = require("effector-action");
|
|
9
9
|
var _skillsUtils = require("@matteappen/skills-utils");
|
|
10
10
|
var _pmProgressHelpers = require("../shared/pmProgress.helpers.js");
|
|
11
|
+
var _TreeNormalizer = require("../shared/TreeNormalizer.js");
|
|
11
12
|
var _session = require("effector-storage/session");
|
|
12
13
|
var _pmProgressConstants = require("../shared/pmProgress.constants.js");
|
|
13
14
|
class PmTreeModel {
|
|
@@ -98,12 +99,13 @@ class PmTreeModel {
|
|
|
98
99
|
target: this.setDomains
|
|
99
100
|
});
|
|
100
101
|
}
|
|
101
|
-
initTreeFx = (0, _effector.createEffect)(({
|
|
102
|
+
initTreeFx = (0, _effector.createEffect)(async ({
|
|
102
103
|
user
|
|
103
104
|
}) => {
|
|
104
|
-
|
|
105
|
+
const [tree, stats] = await Promise.all([this.api.getTreeFx(user.setting.practiceModeTreeId), this.api.getStatisticsFx({
|
|
105
106
|
entityIds: [user._id]
|
|
106
107
|
})]);
|
|
108
|
+
return [_TreeNormalizer.TreeNormalizer.normalize(tree), stats];
|
|
107
109
|
});
|
|
108
110
|
getTreeContextFx = (0, _effector.attach)({
|
|
109
111
|
source: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_effector","require","_effectorAction","_skillsUtils","_pmProgressHelpers","_session","_pmProgressConstants","PmTreeModel","$tree","createStore","$stats","$user","setupInitialGrade","createEvent","setDomains","setGrade","$isInitialized","$grade","restore","$domains","$grades","constructor","api","persist","key","SessionStorageKeys","GRADE","store","DOMAINS","createAction","initTreeFx","done","target","fn","params","user","result","tree","stats","getTreeGrades","sample","clock","filter","sessionStorage","getItem","treeGrades","Object","values","treeMapping","node","type","map","attributes","grade","getInitialPmGrade","userGrade","lockedGrades","setting","practiceModeLockedGrades","enrolledGrades","doneData","source","isTreeDataReady","treeWithUserStats","enhanceProgressMatrixData","entityId","_id","name","fullName","getDomainStructure","createEffect","Promise","all","getTreeFx","practiceModeTreeId","getStatisticsFx","entityIds","getTreeContextFx","attach","mapParams","_","Error","effect","treeWithStats","exports"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/model/PmTreeModel.ts"],"mappings":";;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AACA,IAAAC,eAAA,GAAAD,OAAA;AAaA,IAAAE,YAAA,GAAAF,OAAA;AACA,IAAAG,kBAAA,GAAAH,OAAA;AAMA,IAAAI,
|
|
1
|
+
{"version":3,"names":["_effector","require","_effectorAction","_skillsUtils","_pmProgressHelpers","_TreeNormalizer","_session","_pmProgressConstants","PmTreeModel","$tree","createStore","$stats","$user","setupInitialGrade","createEvent","setDomains","setGrade","$isInitialized","$grade","restore","$domains","$grades","constructor","api","persist","key","SessionStorageKeys","GRADE","store","DOMAINS","createAction","initTreeFx","done","target","fn","params","user","result","tree","stats","getTreeGrades","sample","clock","filter","sessionStorage","getItem","treeGrades","Object","values","treeMapping","node","type","map","attributes","grade","getInitialPmGrade","userGrade","lockedGrades","setting","practiceModeLockedGrades","enrolledGrades","doneData","source","isTreeDataReady","treeWithUserStats","enhanceProgressMatrixData","entityId","_id","name","fullName","getDomainStructure","createEffect","Promise","all","getTreeFx","practiceModeTreeId","getStatisticsFx","entityIds","TreeNormalizer","normalize","getTreeContextFx","attach","mapParams","_","Error","effect","treeWithStats","exports"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/model/PmTreeModel.ts"],"mappings":";;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AACA,IAAAC,eAAA,GAAAD,OAAA;AAaA,IAAAE,YAAA,GAAAF,OAAA;AACA,IAAAG,kBAAA,GAAAH,OAAA;AAMA,IAAAI,eAAA,GAAAJ,OAAA;AACA,IAAAK,QAAA,GAAAL,OAAA;AACA,IAAAM,oBAAA,GAAAN,OAAA;AAEO,MAAMO,WAAW,CAAC;EACNC,KAAK,GAAG,IAAAC,qBAAW,EAA6B,IAAI,CAAC;EACrDC,MAAM,GAAG,IAAAD,qBAAW,EAAuB,IAAI,CAAC;EAChDE,KAAK,GAAG,IAAAF,qBAAW,EAAc,IAAI,CAAC;EAEtCG,iBAAiB,GAAG,IAAAC,qBAAW,EAAyB,CAAC;EACzDC,UAAU,GAAG,IAAAD,qBAAW,EAAW,CAAC;EACrCE,QAAQ,GAAG,IAAAF,qBAAW,EAAgB,CAAC;EAEvCG,cAAc,GAAG,IAAAP,qBAAW,EAAC,KAAK,CAAC;EACnCQ,MAAM,GAAG,IAAAC,iBAAO,EAAC,IAAI,CAACH,QAAQ,EAAE,IAAI,CAAC;EACrCI,QAAQ,GAAG,IAAAD,iBAAO,EAAC,IAAI,CAACJ,UAAU,EAAE,EAAE,CAAC;EACvCM,OAAO,GAAG,IAAAX,qBAAW,EAAU,EAAE,CAAC;EAElDY,WAAWA,CAAkBC,GAAkB,EAAE;IAAA,KAApBA,GAAkB,GAAlBA,GAAkB;IAC7C,IAAAC,gBAAO,EAAC;MAAEC,GAAG,EAAEC,uCAAkB,CAACC,KAAK;MAAEC,KAAK,EAAE,IAAI,CAACV;IAAO,CAAC,CAAC;IAC9D,IAAAM,gBAAO,EAAC;MAAEC,GAAG,EAAEC,uCAAkB,CAACG,OAAO;MAAED,KAAK,EAAE,IAAI,CAACR;IAAS,CAAC,CAAC;IAElE,IAAAU,4BAAY,EAAC,IAAI,CAACC,UAAU,CAACC,IAAI,EAAE;MACjCC,MAAM,EAAE;QACNxB,KAAK,EAAE,IAAI,CAACA,KAAK;QACjBE,MAAM,EAAE,IAAI,CAACA,MAAM;QACnBC,KAAK,EAAE,IAAI,CAACA,KAAK;QACjBS,OAAO,EAAE,IAAI,CAACA,OAAO;QACrBJ,cAAc,EAAE,IAAI,CAACA,cAAc;QACnCJ,iBAAiB,EAAE,IAAI,CAACA;MAC1B,CAAC;MACDqB,EAAE,EAAEA,CAACD,MAAM,EAAE;QAAEE,MAAM,EAAE;UAAEC;QAAK,CAAC;QAAEC,MAAM,EAAE,CAACC,IAAI,EAAEC,KAAK;MAAE,CAAC,KAAK;QAC3DN,MAAM,CAACxB,KAAK,CAAC6B,IAAI,CAAC;QAClBL,MAAM,CAACtB,MAAM,CAAC4B,KAAK,CAAC;QACpBN,MAAM,CAACrB,KAAK,CAACwB,IAAI,CAAC;QAClBH,MAAM,CAACZ,OAAO,CAAC,IAAAmB,gCAAa,EAACF,IAAI,EAAEF,IAAI,CAAC,CAAC;QACzCH,MAAM,CAACpB,iBAAiB,CAAC;UAAEyB,IAAI;UAAEF;QAAK,CAAC,CAAC;QACxCH,MAAM,CAAChB,cAAc,CAAC,IAAI,CAAC;MAC7B;IACF,CAAC,CAAC;IAEF,IAAAwB,gBAAM,EAAC;MACLC,KAAK,EAAE,IAAI,CAAC7B,iBAAiB;MAC7B8B,MAAM,EAAEA,CAAA,KAAMC,cAAc,CAACC,OAAO,CAACnB,uCAAkB,CAACC,KAAK,CAAC,KAAK,IAAI;MACvEO,EAAE,EAAEA,CAAC;QAAEI,IAAI;QAAEF;MAAK,CAAC,KAAK;QACtB,MAAMU,UAAU,GAAGC,MAAM,CAACC,MAAM,CAACV,IAAI,CAACW,WAAW,CAAC,CAC/CN,MAAM,CAAEO,IAAI,IAAKA,IAAI,CAACC,IAAI,KAAK,OAAO,CAAC,CACvCC,GAAG,CAAEF,IAAI,IAAKA,IAAI,CAACG,UAAU,CAACC,KAAK,CAAC;QAEvC,OAAO,IAAAC,oCAAiB,EAAC;UACvBC,SAAS,EAAEpB,IAAI,CAACkB,KAAK;UACrBR,UAAU;UACVW,YAAY,EAAErB,IAAI,CAACsB,OAAO,CAACC,wBAAwB;UACnDC,cAAc,EAAExB,IAAI,CAACwB;QACvB,CAAC,CAAC;MACJ,CAAC;MACD3B,MAAM,EAAE,IAAI,CAACjB;IACf,CAAC,CAAC;IAEF,IAAAyB,gBAAM,EAAC;MACLC,KAAK,EAAE,CAAC,IAAI,CAACxB,MAAM,EAAE,IAAI,CAACa,UAAU,CAAC8B,QAAQ,CAAC;MAC9CC,MAAM,EAAE;QAAExB,IAAI,EAAE,IAAI,CAAC7B,KAAK;QAAE8B,KAAK,EAAE,IAAI,CAAC5B,MAAM;QAAEyB,IAAI,EAAE,IAAI,CAACxB,KAAK;QAAE0C,KAAK,EAAE,IAAI,CAACpC;MAAO,CAAC;MACtFyB,MAAM,EAAEoB,kCAAe;MACvB7B,EAAE,EAAEA,CAAC;QAAEI,IAAI;QAAEC,KAAK;QAAEH,IAAI;QAAEkB;MAAM,CAAC,KAAK;QACpC,MAAM,CAACU,iBAAiB,CAAC,GAAG,IAAAC,sCAAyB,EACnDlB,MAAM,CAACC,MAAM,CAACV,IAAI,CAACW,WAAW,CAAC,EAC/BV,KAAK,EACL,CAAC;UAAE2B,QAAQ,EAAE9B,IAAI,CAAC+B,GAAG;UAAEC,IAAI,EAAEhC,IAAI,CAACiC;QAAS,CAAC,CAAC,EAC7Cf,KACF,CAAC;QAED,OAAO,IAAAgB,qCAAkB,EAACN,iBAAiB,EAAE1B,IAAI,CAACW,WAAW,CAAC;MAChE,CAAC;MACDhB,MAAM,EAAE,IAAI,CAAClB;IACf,CAAC,CAAC;EACJ;EAEOgB,UAAU,GAAG,IAAAwC,sBAAY,EAAC,OAAO;IAAEnC;EAA0B,CAAC,KAAK;IACxE,MAAM,CAACE,IAAI,EAAEC,KAAK,CAAC,GAAG,MAAMiC,OAAO,CAACC,GAAG,CAAC,CACtC,IAAI,CAAClD,GAAG,CAACmD,SAAS,CAACtC,IAAI,CAACsB,OAAO,CAACiB,kBAAkB,CAAC,EACnD,IAAI,CAACpD,GAAG,CAACqD,eAAe,CAAC;MAAEC,SAAS,EAAE,CAACzC,IAAI,CAAC+B,GAAG;IAAE,CAAC,CAAC,CACpD,CAAC;IACF,OAAO,CAACW,8BAAc,CAACC,SAAS,CAACzC,IAAI,CAAC,EAAEC,KAAK,CAAC;EAChD,CAAC,CAAC;EAEcyC,gBAAgB,GAAG,IAAAC,gBAAM,EAAC;IACxCnB,MAAM,EAAE;MAAExB,IAAI,EAAE,IAAI,CAAC7B,KAAK;MAAE8B,KAAK,EAAE,IAAI,CAAC5B,MAAM;MAAEyB,IAAI,EAAE,IAAI,CAACxB,KAAK;MAAE0C,KAAK,EAAE,IAAI,CAACpC;IAAO,CAAC;IACtFgE,SAAS,EAAEA,CAACC,CAAO,EAAErB,MAAM,KAA6B;MACtD,IAAI,CAAC,IAAAC,kCAAe,EAACD,MAAM,CAAC,EAAE;QAC5B,MAAM,IAAIsB,KAAK,CACb,iFACF,CAAC;MACH;MACA,OAAOtB,MAAM;IACf,CAAC;IACDuB,MAAM,EAAE,IAAAd,sBAAY,EAAC,CAAC;MAAEjC,IAAI;MAAEC,KAAK;MAAEH,IAAI;MAAEkB;IAA8B,CAAC,KAAkB;MAC1F,MAAM,CAACgC,aAAa,CAAC,GAAG,IAAArB,sCAAyB,EAC/ClB,MAAM,CAACC,MAAM,CAACV,IAAI,CAACW,WAAW,CAAC,EAC/BV,KAAK,EACL,CAAC;QAAE2B,QAAQ,EAAE9B,IAAI,CAAC+B,GAAG;QAAEC,IAAI,EAAEhC,IAAI,CAACiC;MAAS,CAAC,CAAC,EAC7Cf,KACF,CAAC;MACD,OAAO;QACLhB,IAAI;QACJC,KAAK;QACLH,IAAI;QACJkD;MACF,CAAC;IACH,CAAC;EACH,CAAC,CAAC;AACJ;AAACC,OAAA,CAAA/E,WAAA,GAAAA,WAAA","ignoreList":[]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.TreeNormalizer = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Some skills from the API lack a valid ability (missing sectionId and functionName),
|
|
9
|
+
* making them impossible to open in the solving flow. This normalizer strips those skills
|
|
10
|
+
* and cascades the cleanup - removing standards, domains, etc. that end up empty.
|
|
11
|
+
*
|
|
12
|
+
* Acts as a single place to sanitize the tree API response before it enters the app.
|
|
13
|
+
* Can be extended with additional normalizations as new edge cases arise.
|
|
14
|
+
*/
|
|
15
|
+
class TreeNormalizer {
|
|
16
|
+
static normalize(response) {
|
|
17
|
+
const skillsMapping = this.getOnlyValidSkills(response.skillsMapping);
|
|
18
|
+
const validIds = new Set(Object.keys(skillsMapping));
|
|
19
|
+
const treeMapping = this.removeEmptyNodes(response.treeMapping, validIds);
|
|
20
|
+
return {
|
|
21
|
+
...response,
|
|
22
|
+
skillsMapping,
|
|
23
|
+
treeMapping
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
static isSkillValid(skill) {
|
|
27
|
+
return Boolean(skill?.ability && (skill.ability.sectionId || skill.ability.functionName));
|
|
28
|
+
}
|
|
29
|
+
static getOnlyValidSkills(mapping) {
|
|
30
|
+
return Object.fromEntries(Object.entries(mapping).filter(([, skill]) => this.isSkillValid(skill)));
|
|
31
|
+
}
|
|
32
|
+
static removeEmptyNodes(treeMapping, validIds) {
|
|
33
|
+
const emptyIds = this.getEmptyNodeIds(treeMapping, validIds);
|
|
34
|
+
return Object.fromEntries(Object.entries(treeMapping).filter(([id]) => !emptyIds.has(id)).map(([id, node]) => [id, {
|
|
35
|
+
...node,
|
|
36
|
+
skills: node.skills.filter(sid => validIds.has(sid)),
|
|
37
|
+
children: node.children.filter(cid => !emptyIds.has(cid))
|
|
38
|
+
}]));
|
|
39
|
+
}
|
|
40
|
+
static getEmptyNodeIds(treeMapping, validIds) {
|
|
41
|
+
const empty = new Set();
|
|
42
|
+
const leafToRoot = Object.entries(treeMapping).sort(([, a], [, b]) => b.parents.length - a.parents.length);
|
|
43
|
+
for (const [id, node] of leafToRoot) {
|
|
44
|
+
const isEmptyLeaf = node.skills.length > 0 && node.skills.every(s => !validIds.has(s));
|
|
45
|
+
const isEmptyParent = node.children.length > 0 && node.children.every(c => empty.has(c));
|
|
46
|
+
if (isEmptyLeaf || isEmptyParent) empty.add(id);
|
|
47
|
+
}
|
|
48
|
+
return empty;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.TreeNormalizer = TreeNormalizer;
|
|
52
|
+
//# sourceMappingURL=TreeNormalizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TreeNormalizer","normalize","response","skillsMapping","getOnlyValidSkills","validIds","Set","Object","keys","treeMapping","removeEmptyNodes","isSkillValid","skill","Boolean","ability","sectionId","functionName","mapping","fromEntries","entries","filter","emptyIds","getEmptyNodeIds","id","has","map","node","skills","sid","children","cid","empty","leafToRoot","sort","a","b","parents","length","isEmptyLeaf","every","s","isEmptyParent","c","add","exports"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/shared/TreeNormalizer.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -4,6 +4,7 @@ import { attach, createEffect, createEvent, createStore, restore, sample } from
|
|
|
4
4
|
import { createAction } from 'effector-action';
|
|
5
5
|
import { enhanceProgressMatrixData } from '@matteappen/skills-utils';
|
|
6
6
|
import { getDomainStructure, getInitialPmGrade, getTreeGrades, isTreeDataReady } from "../shared/pmProgress.helpers.js";
|
|
7
|
+
import { TreeNormalizer } from "../shared/TreeNormalizer.js";
|
|
7
8
|
import { persist } from 'effector-storage/session';
|
|
8
9
|
import { SessionStorageKeys } from "../shared/pmProgress.constants.js";
|
|
9
10
|
export class PmTreeModel {
|
|
@@ -94,12 +95,13 @@ export class PmTreeModel {
|
|
|
94
95
|
target: this.setDomains
|
|
95
96
|
});
|
|
96
97
|
}
|
|
97
|
-
initTreeFx = createEffect(({
|
|
98
|
+
initTreeFx = createEffect(async ({
|
|
98
99
|
user
|
|
99
100
|
}) => {
|
|
100
|
-
|
|
101
|
+
const [tree, stats] = await Promise.all([this.api.getTreeFx(user.setting.practiceModeTreeId), this.api.getStatisticsFx({
|
|
101
102
|
entityIds: [user._id]
|
|
102
103
|
})]);
|
|
104
|
+
return [TreeNormalizer.normalize(tree), stats];
|
|
103
105
|
});
|
|
104
106
|
getTreeContextFx = attach({
|
|
105
107
|
source: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["attach","createEffect","createEvent","createStore","restore","sample","createAction","enhanceProgressMatrixData","getDomainStructure","getInitialPmGrade","getTreeGrades","isTreeDataReady","persist","SessionStorageKeys","PmTreeModel","$tree","$stats","$user","setupInitialGrade","setDomains","setGrade","$isInitialized","$grade","$domains","$grades","constructor","api","key","GRADE","store","DOMAINS","initTreeFx","done","target","fn","params","user","result","tree","stats","clock","filter","sessionStorage","getItem","treeGrades","Object","values","treeMapping","node","type","map","attributes","grade","userGrade","lockedGrades","setting","practiceModeLockedGrades","enrolledGrades","doneData","source","treeWithUserStats","entityId","_id","name","fullName","Promise","all","getTreeFx","practiceModeTreeId","getStatisticsFx","entityIds","getTreeContextFx","mapParams","_","Error","effect","treeWithStats"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/model/PmTreeModel.ts"],"mappings":";;AAAA,SAASA,MAAM,EAAEC,YAAY,EAAEC,WAAW,EAAEC,WAAW,EAAEC,OAAO,EAAEC,MAAM,QAAQ,UAAU;AAC1F,SAASC,YAAY,QAAQ,iBAAiB;AAa9C,SAASC,yBAAyB,QAAQ,0BAA0B;AACpE,SACEC,kBAAkB,EAClBC,iBAAiB,EACjBC,aAAa,EACbC,eAAe,QACV,iCAA8B;AACrC,SAASC,OAAO,QAAQ,0BAA0B;AAClD,SAASC,kBAAkB,QAAQ,mCAAgC;AAEnE,OAAO,MAAMC,WAAW,CAAC;EACNC,KAAK,
|
|
1
|
+
{"version":3,"names":["attach","createEffect","createEvent","createStore","restore","sample","createAction","enhanceProgressMatrixData","getDomainStructure","getInitialPmGrade","getTreeGrades","isTreeDataReady","TreeNormalizer","persist","SessionStorageKeys","PmTreeModel","$tree","$stats","$user","setupInitialGrade","setDomains","setGrade","$isInitialized","$grade","$domains","$grades","constructor","api","key","GRADE","store","DOMAINS","initTreeFx","done","target","fn","params","user","result","tree","stats","clock","filter","sessionStorage","getItem","treeGrades","Object","values","treeMapping","node","type","map","attributes","grade","userGrade","lockedGrades","setting","practiceModeLockedGrades","enrolledGrades","doneData","source","treeWithUserStats","entityId","_id","name","fullName","Promise","all","getTreeFx","practiceModeTreeId","getStatisticsFx","entityIds","normalize","getTreeContextFx","mapParams","_","Error","effect","treeWithStats"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/model/PmTreeModel.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Some skills from the API lack a valid ability (missing sectionId and functionName),
|
|
5
|
+
* making them impossible to open in the solving flow. This normalizer strips those skills
|
|
6
|
+
* and cascades the cleanup - removing standards, domains, etc. that end up empty.
|
|
7
|
+
*
|
|
8
|
+
* Acts as a single place to sanitize the tree API response before it enters the app.
|
|
9
|
+
* Can be extended with additional normalizations as new edge cases arise.
|
|
10
|
+
*/
|
|
11
|
+
export class TreeNormalizer {
|
|
12
|
+
static normalize(response) {
|
|
13
|
+
const skillsMapping = this.getOnlyValidSkills(response.skillsMapping);
|
|
14
|
+
const validIds = new Set(Object.keys(skillsMapping));
|
|
15
|
+
const treeMapping = this.removeEmptyNodes(response.treeMapping, validIds);
|
|
16
|
+
return {
|
|
17
|
+
...response,
|
|
18
|
+
skillsMapping,
|
|
19
|
+
treeMapping
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
static isSkillValid(skill) {
|
|
23
|
+
return Boolean(skill?.ability && (skill.ability.sectionId || skill.ability.functionName));
|
|
24
|
+
}
|
|
25
|
+
static getOnlyValidSkills(mapping) {
|
|
26
|
+
return Object.fromEntries(Object.entries(mapping).filter(([, skill]) => this.isSkillValid(skill)));
|
|
27
|
+
}
|
|
28
|
+
static removeEmptyNodes(treeMapping, validIds) {
|
|
29
|
+
const emptyIds = this.getEmptyNodeIds(treeMapping, validIds);
|
|
30
|
+
return Object.fromEntries(Object.entries(treeMapping).filter(([id]) => !emptyIds.has(id)).map(([id, node]) => [id, {
|
|
31
|
+
...node,
|
|
32
|
+
skills: node.skills.filter(sid => validIds.has(sid)),
|
|
33
|
+
children: node.children.filter(cid => !emptyIds.has(cid))
|
|
34
|
+
}]));
|
|
35
|
+
}
|
|
36
|
+
static getEmptyNodeIds(treeMapping, validIds) {
|
|
37
|
+
const empty = new Set();
|
|
38
|
+
const leafToRoot = Object.entries(treeMapping).sort(([, a], [, b]) => b.parents.length - a.parents.length);
|
|
39
|
+
for (const [id, node] of leafToRoot) {
|
|
40
|
+
const isEmptyLeaf = node.skills.length > 0 && node.skills.every(s => !validIds.has(s));
|
|
41
|
+
const isEmptyParent = node.children.length > 0 && node.children.every(c => empty.has(c));
|
|
42
|
+
if (isEmptyLeaf || isEmptyParent) empty.add(id);
|
|
43
|
+
}
|
|
44
|
+
return empty;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=TreeNormalizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TreeNormalizer","normalize","response","skillsMapping","getOnlyValidSkills","validIds","Set","Object","keys","treeMapping","removeEmptyNodes","isSkillValid","skill","Boolean","ability","sectionId","functionName","mapping","fromEntries","entries","filter","emptyIds","getEmptyNodeIds","id","has","map","node","skills","sid","children","cid","empty","leafToRoot","sort","a","b","parents","length","isEmptyLeaf","every","s","isEmptyParent","c","add"],"sourceRoot":"../../../../../src","sources":["features/pmProgress/shared/TreeNormalizer.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -13,7 +13,7 @@ export declare class PmTreeModel {
|
|
|
13
13
|
readonly $domains: import("effector").StoreWritable<Domain[]>;
|
|
14
14
|
readonly $grades: import("effector").StoreWritable<Grade[]>;
|
|
15
15
|
constructor(api: PmProgressApi);
|
|
16
|
-
initTreeFx: import("effector").Effect<PmProgressGateProps, [TreeMappingResponse, StatsResponse], Error>;
|
|
16
|
+
initTreeFx: import("effector").Effect<PmProgressGateProps, readonly [TreeMappingResponse, StatsResponse], Error>;
|
|
17
17
|
readonly getTreeContextFx: import("effector").Effect<void, TreeContext, Error>;
|
|
18
18
|
}
|
|
19
19
|
//# sourceMappingURL=PmTreeModel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PmTreeModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/model/PmTreeModel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,EACL,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,mBAAmB,EAEpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"PmTreeModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/model/PmTreeModel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,EACL,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,mBAAmB,EAEpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAY/C,qBAAa,WAAW;IAcV,OAAO,CAAC,QAAQ,CAAC,GAAG;IAbhC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwC;IAC1E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,SAAgB,QAAQ,kDAA+B;IAEvD,SAAgB,cAAc,4CAAqB;IACnD,SAAgB,MAAM,kDAA+B;IACrD,SAAgB,QAAQ,6CAA+B;IACvD,SAAgB,OAAO,4CAA2B;gBAErB,GAAG,EAAE,aAAa;IA2DxC,UAAU,uGAMf;IAEF,SAAgB,gBAAgB,sDAwB9B;CACH"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Skill, TreeMappingResponse } from './pmProgress.types';
|
|
2
|
+
/**
|
|
3
|
+
* Some skills from the API lack a valid ability (missing sectionId and functionName),
|
|
4
|
+
* making them impossible to open in the solving flow. This normalizer strips those skills
|
|
5
|
+
* and cascades the cleanup - removing standards, domains, etc. that end up empty.
|
|
6
|
+
*
|
|
7
|
+
* Acts as a single place to sanitize the tree API response before it enters the app.
|
|
8
|
+
* Can be extended with additional normalizations as new edge cases arise.
|
|
9
|
+
*/
|
|
10
|
+
export declare class TreeNormalizer {
|
|
11
|
+
static normalize(response: TreeMappingResponse): TreeMappingResponse;
|
|
12
|
+
static isSkillValid(skill: Skill): boolean;
|
|
13
|
+
private static getOnlyValidSkills;
|
|
14
|
+
private static removeEmptyNodes;
|
|
15
|
+
private static getEmptyNodeIds;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=TreeNormalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeNormalizer.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/shared/TreeNormalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAiB,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAInF;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,mBAAmB;IAOpE,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK;IAIhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAMjC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiB/B,OAAO,CAAC,MAAM,CAAC,eAAe;CAgB/B"}
|
|
@@ -13,7 +13,7 @@ export declare class PmTreeModel {
|
|
|
13
13
|
readonly $domains: import("effector").StoreWritable<Domain[]>;
|
|
14
14
|
readonly $grades: import("effector").StoreWritable<Grade[]>;
|
|
15
15
|
constructor(api: PmProgressApi);
|
|
16
|
-
initTreeFx: import("effector").Effect<PmProgressGateProps, [TreeMappingResponse, StatsResponse], Error>;
|
|
16
|
+
initTreeFx: import("effector").Effect<PmProgressGateProps, readonly [TreeMappingResponse, StatsResponse], Error>;
|
|
17
17
|
readonly getTreeContextFx: import("effector").Effect<void, TreeContext, Error>;
|
|
18
18
|
}
|
|
19
19
|
//# sourceMappingURL=PmTreeModel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PmTreeModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/model/PmTreeModel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,EACL,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,mBAAmB,EAEpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"PmTreeModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/model/PmTreeModel.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,EACL,mBAAmB,EAEnB,aAAa,EAEb,WAAW,EACX,mBAAmB,EAEpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAY/C,qBAAa,WAAW;IAcV,OAAO,CAAC,QAAQ,CAAC,GAAG;IAbhC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwC;IAC1E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,SAAgB,QAAQ,kDAA+B;IAEvD,SAAgB,cAAc,4CAAqB;IACnD,SAAgB,MAAM,kDAA+B;IACrD,SAAgB,QAAQ,6CAA+B;IACvD,SAAgB,OAAO,4CAA2B;gBAErB,GAAG,EAAE,aAAa;IA2DxC,UAAU,uGAMf;IAEF,SAAgB,gBAAgB,sDAwB9B;CACH"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Skill, TreeMappingResponse } from './pmProgress.types';
|
|
2
|
+
/**
|
|
3
|
+
* Some skills from the API lack a valid ability (missing sectionId and functionName),
|
|
4
|
+
* making them impossible to open in the solving flow. This normalizer strips those skills
|
|
5
|
+
* and cascades the cleanup - removing standards, domains, etc. that end up empty.
|
|
6
|
+
*
|
|
7
|
+
* Acts as a single place to sanitize the tree API response before it enters the app.
|
|
8
|
+
* Can be extended with additional normalizations as new edge cases arise.
|
|
9
|
+
*/
|
|
10
|
+
export declare class TreeNormalizer {
|
|
11
|
+
static normalize(response: TreeMappingResponse): TreeMappingResponse;
|
|
12
|
+
static isSkillValid(skill: Skill): boolean;
|
|
13
|
+
private static getOnlyValidSkills;
|
|
14
|
+
private static removeEmptyNodes;
|
|
15
|
+
private static getEmptyNodeIds;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=TreeNormalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeNormalizer.d.ts","sourceRoot":"","sources":["../../../../../../src/features/pmProgress/shared/TreeNormalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAiB,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAInF;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,mBAAmB;IAOpE,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK;IAIhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAMjC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiB/B,OAAO,CAAC,MAAM,CAAC,eAAe;CAgB/B"}
|
package/package.json
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
getTreeGrades,
|
|
20
20
|
isTreeDataReady,
|
|
21
21
|
} from '../shared/pmProgress.helpers'
|
|
22
|
+
import { TreeNormalizer } from '../shared/TreeNormalizer'
|
|
22
23
|
import { persist } from 'effector-storage/session'
|
|
23
24
|
import { SessionStorageKeys } from '../shared/pmProgress.constants'
|
|
24
25
|
|
|
@@ -95,11 +96,12 @@ export class PmTreeModel {
|
|
|
95
96
|
})
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
public initTreeFx = createEffect(({ user }: PmProgressGateProps) => {
|
|
99
|
-
|
|
99
|
+
public initTreeFx = createEffect(async ({ user }: PmProgressGateProps) => {
|
|
100
|
+
const [tree, stats] = await Promise.all([
|
|
100
101
|
this.api.getTreeFx(user.setting.practiceModeTreeId),
|
|
101
102
|
this.api.getStatisticsFx({ entityIds: [user._id] }),
|
|
102
103
|
])
|
|
104
|
+
return [TreeNormalizer.normalize(tree), stats] as const
|
|
103
105
|
})
|
|
104
106
|
|
|
105
107
|
public readonly getTreeContextFx = attach({
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Skill, SkillsMapping, TreeMappingResponse } from './pmProgress.types'
|
|
2
|
+
|
|
3
|
+
type TreeMapping = TreeMappingResponse['treeMapping']
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Some skills from the API lack a valid ability (missing sectionId and functionName),
|
|
7
|
+
* making them impossible to open in the solving flow. This normalizer strips those skills
|
|
8
|
+
* and cascades the cleanup - removing standards, domains, etc. that end up empty.
|
|
9
|
+
*
|
|
10
|
+
* Acts as a single place to sanitize the tree API response before it enters the app.
|
|
11
|
+
* Can be extended with additional normalizations as new edge cases arise.
|
|
12
|
+
*/
|
|
13
|
+
export class TreeNormalizer {
|
|
14
|
+
static normalize(response: TreeMappingResponse): TreeMappingResponse {
|
|
15
|
+
const skillsMapping = this.getOnlyValidSkills(response.skillsMapping)
|
|
16
|
+
const validIds = new Set(Object.keys(skillsMapping))
|
|
17
|
+
const treeMapping = this.removeEmptyNodes(response.treeMapping, validIds)
|
|
18
|
+
return { ...response, skillsMapping, treeMapping }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static isSkillValid(skill: Skill) {
|
|
22
|
+
return Boolean(skill?.ability && (skill.ability.sectionId || skill.ability.functionName))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private static getOnlyValidSkills(mapping: SkillsMapping): SkillsMapping {
|
|
26
|
+
return Object.fromEntries(
|
|
27
|
+
Object.entries(mapping).filter(([, skill]) => this.isSkillValid(skill)),
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private static removeEmptyNodes(treeMapping: TreeMapping, validIds: Set<string>): TreeMapping {
|
|
32
|
+
const emptyIds = this.getEmptyNodeIds(treeMapping, validIds)
|
|
33
|
+
|
|
34
|
+
return Object.fromEntries(
|
|
35
|
+
Object.entries(treeMapping)
|
|
36
|
+
.filter(([id]) => !emptyIds.has(id))
|
|
37
|
+
.map(([id, node]) => [
|
|
38
|
+
id,
|
|
39
|
+
{
|
|
40
|
+
...node,
|
|
41
|
+
skills: node.skills.filter((sid) => validIds.has(sid)),
|
|
42
|
+
children: node.children.filter((cid) => !emptyIds.has(cid)),
|
|
43
|
+
},
|
|
44
|
+
]),
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private static getEmptyNodeIds(treeMapping: TreeMapping, validIds: Set<string>) {
|
|
49
|
+
const empty = new Set<string>()
|
|
50
|
+
|
|
51
|
+
const leafToRoot = Object.entries(treeMapping).sort(
|
|
52
|
+
([, a], [, b]) => b.parents.length - a.parents.length,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
for (const [id, node] of leafToRoot) {
|
|
56
|
+
const isEmptyLeaf = node.skills.length > 0 && node.skills.every((s) => !validIds.has(s))
|
|
57
|
+
const isEmptyParent = node.children.length > 0 && node.children.every((c) => empty.has(c))
|
|
58
|
+
|
|
59
|
+
if (isEmptyLeaf || isEmptyParent) empty.add(id)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return empty
|
|
63
|
+
}
|
|
64
|
+
}
|