@project-sunbird/collection-editor-react 1.0.0 → 1.0.3

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.
Files changed (108) hide show
  1. package/README.md +55 -0
  2. package/dist/api/content.d.ts +1 -1
  3. package/dist/api/framework.d.ts +0 -1
  4. package/dist/api/hierarchy.d.ts +7 -1
  5. package/dist/collection-editor.umd.js +144 -104
  6. package/dist/components/AssetBrowser/AssetBrowser.d.ts +0 -1
  7. package/dist/components/AssignPageNumber/AssignPageNumber.d.ts +0 -1
  8. package/dist/components/BulkUpload/CsvUpload.d.ts +0 -1
  9. package/dist/components/Collaborators/ManageCollaborators.d.ts +0 -1
  10. package/dist/components/CollectionEditor/CollectionEditor.d.ts +0 -1
  11. package/dist/components/ContentPlayer/ContentPlayer.d.ts +0 -1
  12. package/dist/components/ContextualEditor/AssessmentDetailPanel.d.ts +7 -0
  13. package/dist/components/ContextualEditor/Breadcrumb.d.ts +0 -1
  14. package/dist/components/ContextualEditor/ContentEditForm.d.ts +0 -1
  15. package/dist/components/ContextualEditor/ContextualEditor.d.ts +0 -1
  16. package/dist/components/ContextualEditor/TabBar.d.ts +0 -1
  17. package/dist/components/ContextualEditor/TitleAppIcon.d.ts +0 -1
  18. package/dist/components/Dialcode/DialcodePanel.d.ts +0 -1
  19. package/dist/components/LibraryDock/FilterChips.d.ts +0 -1
  20. package/dist/components/LibraryDock/LibraryCard.d.ts +0 -1
  21. package/dist/components/LibraryDock/LibraryDock.d.ts +0 -1
  22. package/dist/components/LibraryDock/LibraryFilterPanel.d.ts +0 -1
  23. package/dist/components/LibraryDock/LibraryPreviewPanel.d.ts +0 -1
  24. package/dist/components/OutlineTree/OutlineTree.d.ts +0 -1
  25. package/dist/components/OutlineTree/TreeNode.d.ts +0 -1
  26. package/dist/components/ProgressStatus/ProgressStatus.d.ts +0 -1
  27. package/dist/components/ResourceReorder/ResourceReorderDialog.d.ts +0 -1
  28. package/dist/components/SparkMetaForm/FormSection.d.ts +0 -1
  29. package/dist/components/SparkMetaForm/SparkMetaForm.d.ts +0 -1
  30. package/dist/components/SparkMetaForm/fields/AppIconField.d.ts +0 -1
  31. package/dist/components/SparkMetaForm/fields/AppIconPickerModal.d.ts +0 -1
  32. package/dist/components/SparkMetaForm/fields/ChipGroupField.d.ts +0 -1
  33. package/dist/components/SparkMetaForm/fields/DateTimeField.d.ts +0 -1
  34. package/dist/components/SparkMetaForm/fields/DialcodeInputField.d.ts +0 -1
  35. package/dist/components/SparkMetaForm/fields/KeywordSuggestField.d.ts +0 -1
  36. package/dist/components/SparkMetaForm/fields/LicenseSelectField.d.ts +0 -1
  37. package/dist/components/SparkMetaForm/fields/MultiSelectField.d.ts +0 -1
  38. package/dist/components/SparkMetaForm/fields/NestedSelectField.d.ts +0 -1
  39. package/dist/components/SparkMetaForm/fields/PolicyCardField.d.ts +9 -0
  40. package/dist/components/SparkMetaForm/fields/RadioField.d.ts +0 -1
  41. package/dist/components/SparkMetaForm/fields/SelectField.d.ts +0 -1
  42. package/dist/components/SparkMetaForm/fields/TextField.d.ts +0 -1
  43. package/dist/components/SparkMetaForm/hooks/useCascade.d.ts +0 -1
  44. package/dist/components/SparkMetaForm/hooks/useFieldPrepare.d.ts +9 -1
  45. package/dist/components/SparkMetaForm/hooks/useFieldPrepare.learningPath.test.d.ts +1 -0
  46. package/dist/components/SplitBuilderShell/SplitBuilderShell.d.ts +0 -1
  47. package/dist/components/Topbar/Topbar.d.ts +0 -1
  48. package/dist/components/UnitContentList/AssessmentSlotItem.d.ts +7 -0
  49. package/dist/components/UnitContentList/ContentRow.d.ts +0 -1
  50. package/dist/components/UnitContentList/SkillPicker.d.ts +15 -0
  51. package/dist/components/UnitContentList/UnitContentList.d.ts +1 -1
  52. package/dist/components/modals/ConfirmDialog.d.ts +0 -1
  53. package/dist/components/modals/PublishChecklist.d.ts +0 -1
  54. package/dist/components/modals/QualityParamsModal.d.ts +0 -1
  55. package/dist/components/modals/UnsavedChangesModal.d.ts +0 -1
  56. package/dist/components/shared/Button.d.ts +0 -1
  57. package/dist/components/shared/Card.d.ts +0 -1
  58. package/dist/components/shared/Chip.d.ts +0 -1
  59. package/dist/components/shared/CourseDetailsPanel.d.ts +11 -0
  60. package/dist/components/shared/DropZone.d.ts +0 -1
  61. package/dist/components/shared/LanguageSelector/LanguageSelector.d.ts +0 -1
  62. package/dist/components/shared/LearningPathIcon.d.ts +6 -0
  63. package/dist/components/shared/Spinner.d.ts +0 -1
  64. package/dist/components/shared/index.d.ts +2 -0
  65. package/dist/dev-mock-api.d.ts +1 -0
  66. package/dist/hooks/useAssessmentSlots.d.ts +16 -0
  67. package/dist/hooks/useChannelData.d.ts +0 -1
  68. package/dist/hooks/useContentType.d.ts +0 -1
  69. package/dist/hooks/useEditorInit.d.ts +0 -1
  70. package/dist/hooks/useFramework.d.ts +0 -1
  71. package/dist/hooks/useLabels.d.ts +0 -1
  72. package/dist/hooks/useLibrary.d.ts +30 -1
  73. package/dist/hooks/useLibrary.test.d.ts +1 -0
  74. package/dist/hooks/useLibraryTargetLabel.d.ts +1 -0
  75. package/dist/hooks/useQumlContent.d.ts +0 -1
  76. package/dist/hooks/useSaveHierarchy.d.ts +6 -0
  77. package/dist/hooks/useSaveHierarchy.test.d.ts +1 -0
  78. package/dist/hooks/useSkillCategory.d.ts +24 -0
  79. package/dist/hooks/useSkillCategory.test.d.ts +1 -0
  80. package/dist/hooks/useSkillScope.d.ts +14 -0
  81. package/dist/hooks/useSkillScope.test.d.ts +1 -0
  82. package/dist/hooks/useToolbarActions.d.ts +0 -1
  83. package/dist/hooks/useTree.d.ts +0 -1
  84. package/dist/i18n/index.d.ts +0 -1
  85. package/dist/i18n/locales/ar.json.d.ts +92 -0
  86. package/dist/i18n/locales/en.json.d.ts +92 -0
  87. package/dist/i18n/locales/fr.json.d.ts +92 -0
  88. package/dist/i18n/locales/pt.json.d.ts +92 -0
  89. package/dist/index.cjs +144 -104
  90. package/dist/index.d.ts +1 -0
  91. package/dist/index.js +10861 -11055
  92. package/dist/services/quml/QumlPlayerService.d.ts +0 -1
  93. package/dist/store/editor.store.d.ts +3 -1
  94. package/dist/store/i18n.store.d.ts +0 -1
  95. package/dist/store/library.store.d.ts +0 -1
  96. package/dist/store/tree.store.d.ts +8 -3
  97. package/dist/store/tree.store.learningPath.test.d.ts +1 -0
  98. package/dist/store/ui.store.d.ts +2 -0
  99. package/dist/style.css +1 -1
  100. package/dist/types/content.d.ts +2 -0
  101. package/dist/types/framework.d.ts +4 -0
  102. package/dist/types/profile.d.ts +30 -0
  103. package/dist/types/profile.test.d.ts +1 -0
  104. package/dist/utils/lpStructure.d.ts +151 -0
  105. package/dist/utils/lpStructure.test.d.ts +1 -0
  106. package/dist/utils/validateRequiredFields.d.ts +0 -1
  107. package/dist/web-component/configRoundTrip.test.d.ts +1 -0
  108. package/package.json +13 -4
@@ -0,0 +1,151 @@
1
+ import { INode } from '../types/editor';
2
+ export interface HierarchyLeafLike {
3
+ objectType?: string;
4
+ mimeType?: string;
5
+ children?: HierarchyLeafLike[];
6
+ }
7
+ /**
8
+ * True iff the course has at least one leaf and every leaf is a QuML
9
+ * QuestionSet — legacy ECML assessment resources
10
+ * (application/vnd.ekstep.ecml-archive) do NOT qualify even though they're
11
+ * historically labelled "assessment" content. An empty course (no leaves at
12
+ * all) is not an assessment course.
13
+ */
14
+ export declare function isAssessmentCourse(course: HierarchyLeafLike): boolean;
15
+ export interface AssessmentCourseInfo {
16
+ qualifies: boolean;
17
+ /** The course's full metadata from its own hierarchy read (children stripped).
18
+ * Needed because composite-search results only carry the LP framework's
19
+ * skill field — a course tagged under a different framework (e.g. USF)
20
+ * would otherwise land in the tree without its framework or skill tags. */
21
+ meta: Record<string, unknown>;
22
+ }
23
+ export declare function getAssessmentCourseInfo(courseId: string): Promise<AssessmentCourseInfo>;
24
+ export declare function checkAssessmentCourse(courseId: string): Promise<boolean>;
25
+ export declare function clearAssessmentCourseCache(): void;
26
+ /**
27
+ * Repairs a freshly-loaded LP tree (useEditorInit, after readHierarchy).
28
+ * The hierarchy read undoes two editor-local invariants:
29
+ * - mapToINode marks linked courses (collection mimeType) as folders and
30
+ * expands their internal children — in the LP tree courses are terminal
31
+ * leaves, so re-flatten them;
32
+ * - the isAssessmentCourse flag is local-only (stripped from saves), so
33
+ * without it no Level is recognized as a pre/post slot and "Skills
34
+ * covered"/slot rules read the path as having no assessments. Recompute
35
+ * it from the course's expanded subtree when the read included one, else
36
+ * (single-course first/last Levels only) via a checkAssessmentCourse read.
37
+ */
38
+ export declare function normalizeLearningPathTree(root: INode): Promise<INode>;
39
+ export type LevelRole = 'pre' | 'post' | 'levelAssessment' | 'content';
40
+ export declare function isAssessmentLevel(level: INode | undefined): boolean;
41
+ /**
42
+ * getLevelRole(levelIndex, levelCount, hasAssessmentCourse) → role.
43
+ * Level[0] wrapping an assessment course is Prior/diagnostic ("pre");
44
+ * Level[levelCount-1] wrapping one is Outcome/summative ("post"); an
45
+ * assessment course inside any other Level is a Level assessment; anything
46
+ * else is a regular content Level. When levelCount === 1 the sole Level is
47
+ * treated as "pre" (index-0 check wins the tie) rather than "post".
48
+ */
49
+ export declare function getLevelRole(levelIndex: number, levelCount: number, hasAssessmentCourse: boolean): LevelRole;
50
+ /**
51
+ * Display info for one of root's Level children, keyed by id — same
52
+ * numbering rule TreeNode uses for its "Level N • {name}" row (assessment
53
+ * slots excluded from the count), reused by the Course-detail page's
54
+ * "Back to {label}" button so the two stay consistent.
55
+ */
56
+ export declare function getLevelDisplayInfo(levels: INode[], levelId: string): {
57
+ role: 'pre' | 'post' | 'level';
58
+ levelNumber: number | null;
59
+ } | null;
60
+ /** Whether the pre (index 0) / post (last index) assessment slot already
61
+ * wraps an assessment course, given root's current Level children. */
62
+ export declare function isAssessmentSlotFilled(levels: INode[], slot: 'pre' | 'post'): boolean;
63
+ /** Whether `level` (a direct child of root) is genuinely the pre/post
64
+ * assessment slot — position AND shape, unlike bare `isAssessmentLevel`.
65
+ * For callers (outside this module) that hold the level object rather
66
+ * than its index. */
67
+ export declare function isPrePostSlot(levels: INode[], level: INode | undefined): boolean;
68
+ /**
69
+ * Which pre/post assessment slot (if any) is open to receive a newly-linked
70
+ * assessment course, given root's current Level children. Pre is checked
71
+ * first, so a lone empty path always fills "pre" before "post" — matching
72
+ * getLevelRole's tie-break for levelCount === 1. Returns null once both
73
+ * slots are already wrapping an assessment course.
74
+ */
75
+ export declare function resolveOpenAssessmentSlot(levels: INode[]): 'pre' | 'post' | null;
76
+ /**
77
+ * Guards reorder of root's direct Level children: the pre-assessment Level
78
+ * (if any) must stay pinned at index 0 and the post-assessment Level (if any)
79
+ * must stay pinned at the last index; reordering is only free for the
80
+ * content Levels between them. Simulates the same splice-based move
81
+ * `reorderInParent` performs and checks the pinned Levels didn't shift,
82
+ * rather than hand-deriving index-shift arithmetic.
83
+ */
84
+ export declare function canReorderLevel(levels: INode[], fromIndex: number, toIndex: number): boolean;
85
+ /**
86
+ * Guards adding a course into a Level (doc rules, Phase 2 item 4): a
87
+ * pre/post assessment slot holds exactly one course, ever; a content Level
88
+ * allows any number of regular courses plus at most one Level assessment (a
89
+ * course flagged isAssessmentCourse). `isTargetPrePostSlot` must be computed
90
+ * via `isPrePostSlot` (position-aware) — bare shape (`isAssessmentLevel`)
91
+ * alone would also match a content Level whose only current course happens
92
+ * to be its Level assessment, wrongly blocking further regular courses on
93
+ * an otherwise-open Level.
94
+ */
95
+ export declare function canAddCourseToLevel(level: INode | undefined, incomingIsAssessmentCourse: boolean, isTargetPrePostSlot: boolean): boolean;
96
+ /**
97
+ * The LP root's explicitly-chosen Curriculum (framework) — from a prior save
98
+ * or the current session's Curriculum field, checked via treeCache first
99
+ * since a live edit lands there before a save round-trips it into
100
+ * root.metadata. Deliberately NOT the same as the channel/context default
101
+ * framework (useEditorStore's contentFramework, resolved so *something*
102
+ * exists to browse/filter by before the author has chosen anything) — that
103
+ * fallback must never be mistaken for a real choice, or courses linked
104
+ * under it get pruned the moment a real Curriculum is set, and the Library
105
+ * would silently scope itself to a framework the author never picked.
106
+ */
107
+ export declare function getExplicitCurriculum(root: INode | undefined, treeCache: Record<string, Record<string, unknown>>): string | undefined;
108
+ export declare function hasExplicitCurriculum(root: INode | undefined, treeCache: Record<string, Record<string, unknown>>): boolean;
109
+ /**
110
+ * "Skills covered" (root summary, Phase 4): the union of skills tagged
111
+ * across the Prior Assessment, each Level's *selected* skills, and the
112
+ * Outcome Assessment — never skills scraped from linked courses' content.
113
+ * Both assessment Levels (their course's tags) and content Levels (their
114
+ * own selection) read the SAME resolved skillCategoryCode metadata field —
115
+ * never the reserved Sunbird `competencies` field, whose platform schema
116
+ * expects competency-ontology objects, not plain framework-term strings.
117
+ */
118
+ /**
119
+ * "Path shape" (root summary, Phase 4): level count excludes the pre/post
120
+ * assessment slots (design: "Neither counts as a level"); course count
121
+ * includes every linked course, assessment courses included.
122
+ */
123
+ export declare function computePathShape(root: INode | undefined): {
124
+ levelCount: number;
125
+ courseCount: number;
126
+ };
127
+ export declare function computeSkillsCovered(root: INode | undefined, skillCategoryCode: string | undefined): string[];
128
+ export interface LpValidationIssue {
129
+ code: string;
130
+ message: string;
131
+ nodeId?: string;
132
+ }
133
+ export declare const REQUIRES_PRIOR_POLICIES: Set<string>;
134
+ /**
135
+ * Every synchronous (no network) LP publish rule: consumption policy set;
136
+ * prior assessment required only for Diagnostic/PriorLearning (not Fixed —
137
+ * confirmed open question #1); outcome assessment required always; pre/post
138
+ * slot purity; every content Level has ≥1 course and ≥1 in-scope skill; no
139
+ * empty Levels; every linked course carries a skill tag; no duplicate course
140
+ * across the path. `skillScope` empty means "no scope constraint yet"
141
+ * (matches useSkillScope's manual-fallback catalog, not an empty scope).
142
+ */
143
+ export declare function validateLearningPathStructure(root: INode | undefined, skillCategoryCode: string | undefined, skillScope: string[]): LpValidationIssue[];
144
+ /**
145
+ * Re-verifies the pre/post assessment courses are STILL question-set-only at
146
+ * publish time (Phase 1 item 6 / Phase 5: "the course may have changed since
147
+ * it was linked"). Separate from validateLearningPathStructure because it
148
+ * requires a network read; callers should run it alongside the sync checks,
149
+ * not instead of them.
150
+ */
151
+ export declare function revalidateAssessmentSlots(root: INode | undefined): Promise<LpValidationIssue[]>;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,6 @@
1
1
  import { INode } from '../types/editor';
2
2
  import { IFrameworkDetails } from '../types/framework';
3
3
  import { IPrepareContext } from '../components/SparkMetaForm/hooks/useFieldPrepare';
4
-
5
4
  export interface MissingFieldsReport {
6
5
  nodeId: string;
7
6
  nodeName: string;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@project-sunbird/collection-editor-react",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -57,12 +57,21 @@
57
57
  "@vitejs/plugin-react": "^4.3.1",
58
58
  "sass": "^1.77.6",
59
59
  "typescript": "^5.5.3",
60
- "vite": "^5.3.4",
61
- "vite-plugin-dts": "^3.9.1",
62
- "vitest": "^2.0.3"
60
+ "vite": "^6.4.3",
61
+ "vite-plugin-dts": "^5.0.3",
62
+ "vitest": "^3.2.7"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "react": "^18.0.0 || ^19.0.0",
66
66
  "react-dom": "^18.0.0 || ^19.0.0"
67
+ },
68
+ "overrides": {
69
+ "@microsoft/api-extractor": {
70
+ "lodash": "^4.18.0",
71
+ "minimatch": "^3.1.3"
72
+ },
73
+ "@microsoft/tsdoc-config": {
74
+ "ajv": "^6.14.0"
75
+ }
67
76
  }
68
77
  }