Implemented student view. Added feedback view
This commit is contained in:
		
							parent
							
								
									82e92eed45
								
							
						
					
					
						commit
						456e9b503e
					
				
					 17 changed files with 892 additions and 377 deletions
				
			
		
							
								
								
									
										2
									
								
								amd/build/report-viewer-components.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								amd/build/report-viewer-components.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								amd/build/studyplan-editor-components.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								amd/build/studyplan-editor-components.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								amd/build/util/string-helper.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								amd/build/util/string-helper.min.js
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
define("local_treestudyplan/util/string-helper",["exports","core/str"],(function(_exports,_str){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.load_stringkeys=function(string_keys){var _loop2=function(idx){var stringkeys=[];for(var i in string_keys[idx]){var parts=string_keys[idx][i].textkey.split("$"),identifier=parts[0],component=parts.length>1?parts[1]:"local_treestudyplan";stringkeys.push({key:identifier,component:component})}getstr_func(stringkeys).then((function(strings){for(var _i in strings){var s=strings[_i];string_keys[idx][_i].text=s}}))};for(var idx in string_keys)_loop2(idx);return string_keys},_exports.load_strings=function(strings){var _loop=function(idx){var stringkeys=[];for(var handle in strings[idx]){var parts=strings[idx][handle].split(/[$@]/),identifier=parts[0],component=parts.length>1?parts[1]:"local_treestudyplan";stringkeys.push({key:identifier,component:component})}getstr_func(stringkeys).then((function(str){var i=0;for(var _key in strings[idx])strings[idx][_key]=str[i],i++}))};for(var idx in strings)_loop(idx);return strings},_exports.strformat=function(str,values){return str.replace(/\{(\w+)\}/g,(function(m,m1){return m1&&values.hasOwnProperty(m1)?values[m1]:m}))};var getstr_func=void 0!==_str.getStrings?_str.getStrings:_str.get_strings}));
 | 
			
		||||
define("local_treestudyplan/util/string-helper",["exports","core/str"],(function(_exports,_str){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.load_stringkeys=function(string_keys){for(let idx in string_keys){let stringkeys=[];for(const i in string_keys[idx]){let parts=string_keys[idx][i].textkey.split("$"),identifier=parts[0],component=parts.length>1?parts[1]:"local_treestudyplan";stringkeys.push({key:identifier,component:component})}getstr_func(stringkeys).then((function(strings){for(const i in strings){const s=strings[i];string_keys[idx][i].text=s}}))}return string_keys},_exports.load_strings=function(strings){for(let idx in strings){let stringkeys=[];for(const handle in strings[idx]){let parts=strings[idx][handle].split(/[$@]/),identifier=parts[0],component=parts.length>1?parts[1]:"local_treestudyplan";stringkeys.push({key:identifier,component:component})}getstr_func(stringkeys).then((function(str){let i=0;for(const handle in strings[idx])strings[idx][handle]=str[i],i++}))}return strings},_exports.strformat=function(str,values){return str.replace(/\{(\w+)\}/g,((m,m1)=>m1&&values.hasOwnProperty(m1)?values[m1]:m))};const getstr_func=void 0!==_str.getStrings?_str.getStrings:_str.get_strings}));
 | 
			
		||||
 | 
			
		||||
//# sourceMappingURL=string-helper.min.js.map
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +1 @@
 | 
			
		|||
{"version":3,"file":"string-helper.min.js","sources":["../../src/util/string-helper.js"],"sourcesContent":["import {get_strings} from 'core/str';\nimport {getStrings} from 'core/str';\n\n/* Determine the proper getstrings function to use (MDL4.3+ recommends use of getStrings, which is jquery independent) */\nconst getstr_func = (getStrings !== undefined)?getStrings:get_strings;\n\n/**\n * Load the translation of strings from a strings object\n * @param {Object} strings The map of strings\n * @returns {Object} The map with strings loaded in\n */\nexport function load_strings(strings){\n    for(let idx in strings){\n        let stringkeys = [];\n        for(const handle in  strings[idx]){\n            const key = strings[idx][handle];\n            let parts = key.split(/[$@]/);\n            let identifier = parts[0];\n            let component = (parts.length > 1)?parts[1]:'local_treestudyplan';\n            stringkeys.push({ key: identifier, component: component});\n        }\n        getstr_func(stringkeys).then(function(str){\n            let i = 0;\n            for(const key in strings[idx]){\n                strings[idx][key] = str[i];\n                i++;\n            }\n        });\n    }\n\n    return strings;\n}\n\n/**\n * Load the translation of strings from a strings object based on keys\n * Used for loading values for a drop down menu or the like\n * @param {Object} string_keys The map of stringkeys\n * @returns {Object} The map with strings loaded in\n */\nexport function load_stringkeys(string_keys){\n    for(let idx in string_keys){\n        // Get text strings for condition settings\n        let stringkeys = [];\n        for(const i in  string_keys[idx]){\n            const key = string_keys[idx][i].textkey;\n            let parts = key.split(\"$\");\n            let identifier = parts[0];\n            let component = (parts.length > 1)?parts[1]:'local_treestudyplan';\n            stringkeys.push({ key: identifier, component: component});\n        }\n        getstr_func(stringkeys).then(function(strings){\n            for(const i in strings) {\n                const s = strings[i];\n                const l = string_keys[idx][i];\n                l.text = s;\n            }\n        });\n    }\n    return string_keys;\n}\n\n/**\n * String formatting function - replaces {name} in string by value of same key in values parameter\n * @param {string} str String t\n * @param {object} values Object containing keys to replace {key} strings with\n * @returns Formatted string\n */\nexport function strformat(str,values) {\n    return str.replace(/\\{(\\w+)\\}/g, (m, m1) => {\n        if (m1 && values.hasOwnProperty(m1)) {\n            return values[m1];\n        } else {\n            return m;\n        }\n    });\n}"],"names":["string_keys","idx","stringkeys","i","parts","textkey","split","identifier","component","length","push","key","getstr_func","then","strings","s","text","handle","str","values","replace","m","m1","hasOwnProperty","undefined","getStrings","get_strings"],"mappings":"0LAuCgCA,iCACpBC,SAEAC,WAAa,OACb,IAAMC,KAAMH,YAAYC,KAAK,KAEzBG,MADQJ,YAAYC,KAAKE,GAAGE,QAChBC,MAAM,KAClBC,WAAaH,MAAM,GACnBI,UAAaJ,MAAMK,OAAS,EAAGL,MAAM,GAAG,sBAC5CF,WAAWQ,KAAK,CAAEC,IAAKJ,WAAYC,UAAWA,YAElDI,YAAYV,YAAYW,MAAK,SAASC,aAC9B,IAAMX,MAAKW,QAAS,KACdC,EAAID,QAAQX,IACRH,YAAYC,KAAKE,IACzBa,KAAOD,WAdjB,IAAId,OAAOD,mBAAPC,YAkBDD,4CA/CkBc,4BACjBb,SACAC,WAAa,OACb,IAAMe,UAAWH,QAAQb,KAAK,KAE1BG,MADQU,QAAQb,KAAKgB,QACTX,MAAM,QAClBC,WAAaH,MAAM,GACnBI,UAAaJ,MAAMK,OAAS,EAAGL,MAAM,GAAG,sBAC5CF,WAAWQ,KAAK,CAAEC,IAAKJ,WAAYC,UAAWA,YAElDI,YAAYV,YAAYW,MAAK,SAASK,SAC9Bf,EAAI,MACJ,IAAMQ,QAAOG,QAAQb,KACrBa,QAAQb,KAAKU,MAAOO,IAAIf,GACxBA,YAbR,IAAIF,OAAOa,cAAPb,YAkBDa,qCAqCeI,IAAIC,eACnBD,IAAIE,QAAQ,cAAc,SAACC,EAAGC,WAC7BA,IAAMH,OAAOI,eAAeD,IACrBH,OAAOG,IAEPD,UApEbT,iBAA8BY,IAAfC,gBAA0BA,gBAAWC"}
 | 
			
		||||
{"version":3,"file":"string-helper.min.js","sources":["../../src/util/string-helper.js"],"sourcesContent":["import {get_strings} from 'core/str';\nimport {getStrings} from 'core/str';\n\n/* Determine the proper getstrings function to use (MDL4.3+ recommends use of getStrings, which is jquery independent) */\nconst getstr_func = (getStrings !== undefined)?getStrings:get_strings;\n\n/**\n * Load the translation of strings from a strings object\n * @param {Object} strings The map of strings\n * @returns {Object} The map with strings loaded in\n */\nexport function load_strings(strings){\n    for(let idx in strings){\n        let stringkeys = [];\n        for(const handle in  strings[idx]){\n            const key = strings[idx][handle];\n            let parts = key.split(/[$@]/);\n            let identifier = parts[0];\n            let component = (parts.length > 1)?parts[1]:'local_treestudyplan';\n            stringkeys.push({ key: identifier, component: component});\n        }\n        getstr_func(stringkeys).then(function(str){\n            let i = 0;\n            for(const handle in strings[idx]){\n                strings[idx][handle] = str[i];\n                i++;\n            }\n        });\n    }\n\n    return strings;\n}\n\n/**\n * Load the translation of strings from a strings object based on keys\n * Used for loading values for a drop down menu or the like\n * @param {Object} string_keys The map of stringkeys\n * @returns {Object} The map with strings loaded in\n */\nexport function load_stringkeys(string_keys){\n    for(let idx in string_keys){\n        // Get text strings for condition settings\n        let stringkeys = [];\n        for(const i in  string_keys[idx]){\n            const key = string_keys[idx][i].textkey;\n            let parts = key.split(\"$\");\n            let identifier = parts[0];\n            let component = (parts.length > 1)?parts[1]:'local_treestudyplan';\n            stringkeys.push({ key: identifier, component: component});\n        }\n        getstr_func(stringkeys).then(function(strings){\n            for(const i in strings) {\n                const s = strings[i];\n                const l = string_keys[idx][i];\n                l.text = s;\n            }\n        });\n    }\n    return string_keys;\n}\n\n/**\n * String formatting function - replaces {name} in string by value of same key in values parameter\n * @param {string} str String t\n * @param {object} values Object containing keys to replace {key} strings with\n * @returns Formatted string\n */\nexport function strformat(str,values) {\n    return str.replace(/\\{(\\w+)\\}/g, (m, m1) => {\n        if (m1 && values.hasOwnProperty(m1)) {\n            return values[m1];\n        } else {\n            return m;\n        }\n    });\n}"],"names":["string_keys","idx","stringkeys","i","parts","textkey","split","identifier","component","length","push","key","getstr_func","then","strings","s","text","handle","str","values","replace","m","m1","hasOwnProperty","undefined","getStrings","get_strings"],"mappings":"0LAuCgCA,iBACxB,IAAIC,OAAOD,YAAY,KAEnBE,WAAa,OACb,MAAMC,KAAMH,YAAYC,KAAK,KAEzBG,MADQJ,YAAYC,KAAKE,GAAGE,QAChBC,MAAM,KAClBC,WAAaH,MAAM,GACnBI,UAAaJ,MAAMK,OAAS,EAAGL,MAAM,GAAG,sBAC5CF,WAAWQ,KAAK,CAAEC,IAAKJ,WAAYC,UAAWA,YAElDI,YAAYV,YAAYW,MAAK,SAASC,aAC9B,MAAMX,KAAKW,QAAS,OACdC,EAAID,QAAQX,GACRH,YAAYC,KAAKE,GACzBa,KAAOD,aAIdf,4CA/CkBc,aACrB,IAAIb,OAAOa,QAAQ,KACfZ,WAAa,OACb,MAAMe,UAAWH,QAAQb,KAAK,KAE1BG,MADQU,QAAQb,KAAKgB,QACTX,MAAM,QAClBC,WAAaH,MAAM,GACnBI,UAAaJ,MAAMK,OAAS,EAAGL,MAAM,GAAG,sBAC5CF,WAAWQ,KAAK,CAAEC,IAAKJ,WAAYC,UAAWA,YAElDI,YAAYV,YAAYW,MAAK,SAASK,SAC9Bf,EAAI,MACJ,MAAMc,UAAUH,QAAQb,KACxBa,QAAQb,KAAKgB,QAAUC,IAAIf,GAC3BA,cAKLW,qCAqCeI,IAAIC,eACnBD,IAAIE,QAAQ,cAAc,CAACC,EAAGC,KAC7BA,IAAMH,OAAOI,eAAeD,IACrBH,OAAOG,IAEPD,WApEbT,iBAA8BY,IAAfC,gBAA0BA,gBAAWC"}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -237,6 +237,11 @@ export default {
 | 
			
		|||
            competency: {
 | 
			
		||||
                competency_not_configured: "competency_not_configured",
 | 
			
		||||
                configure_competency: "configure_competency",
 | 
			
		||||
                when: "when",
 | 
			
		||||
                required: "required",
 | 
			
		||||
                points: "points@core_grades",
 | 
			
		||||
                heading: "competency_heading",
 | 
			
		||||
                details: "competency_details",
 | 
			
		||||
            },
 | 
			
		||||
            badge: {
 | 
			
		||||
                share_badge: "share_badge",
 | 
			
		||||
| 
						 | 
				
			
			@ -3191,7 +3196,7 @@ export default {
 | 
			
		|||
                    <t-item-course-competency
 | 
			
		||||
                        v-if='!!value.course.competency'
 | 
			
		||||
                        v-model='value.course.competency'
 | 
			
		||||
                        :course='value.course'
 | 
			
		||||
                        :item='value'
 | 
			
		||||
                        ></t-item-course-competency>
 | 
			
		||||
 | 
			
		||||
                    <template #modal-footer="{ ok, cancel, hide }" >
 | 
			
		||||
| 
						 | 
				
			
			@ -3410,10 +3415,10 @@ export default {
 | 
			
		|||
                    type: Boolean,
 | 
			
		||||
                    default: false,
 | 
			
		||||
                },
 | 
			
		||||
                course: {
 | 
			
		||||
                item: {
 | 
			
		||||
                    type: Object,
 | 
			
		||||
                    default: function(){ return {};},
 | 
			
		||||
                },
 | 
			
		||||
                    default: function(){ return { id: null};},
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            data() {
 | 
			
		||||
                return {
 | 
			
		||||
| 
						 | 
				
			
			@ -3421,19 +3426,7 @@ export default {
 | 
			
		|||
                };
 | 
			
		||||
            },
 | 
			
		||||
            created(){
 | 
			
		||||
                const self = this;
 | 
			
		||||
                // Get text strings for condition settings
 | 
			
		||||
                let stringkeys = [];
 | 
			
		||||
                for(const key in  this.text){
 | 
			
		||||
                    stringkeys.push({ key: key, component: 'local_treestudyplan'});
 | 
			
		||||
                }
 | 
			
		||||
                get_strings(stringkeys).then(function(strings){
 | 
			
		||||
                    let i = 0;
 | 
			
		||||
                    for(const key in  self.text){
 | 
			
		||||
                        self.text[key] = strings[i];
 | 
			
		||||
                        i++;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            },
 | 
			
		||||
            computed: {
 | 
			
		||||
                hasCompletions() {
 | 
			
		||||
| 
						 | 
				
			
			@ -3448,25 +3441,6 @@ export default {
 | 
			
		|||
                },
 | 
			
		||||
            },
 | 
			
		||||
            methods: {
 | 
			
		||||
                completion_icon(completion) {
 | 
			
		||||
                    switch(completion){
 | 
			
		||||
                        case "progress":
 | 
			
		||||
                            return "exclamation-circle";
 | 
			
		||||
                        case "complete":
 | 
			
		||||
                            return "check-circle";
 | 
			
		||||
                        case "complete-pass":
 | 
			
		||||
                            return "check-circle";
 | 
			
		||||
                        case "complete-fail":
 | 
			
		||||
                            return "times-circle";
 | 
			
		||||
                        default: // case "incomplete"
 | 
			
		||||
                            return "circle-o";
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
 | 
			
		||||
                completion_tag(cgroup){
 | 
			
		||||
                    return cgroup.completion?'completed':'incomplete';
 | 
			
		||||
                },
 | 
			
		||||
 | 
			
		||||
                pathtags(competency) {
 | 
			
		||||
                    const path = competency.path;
 | 
			
		||||
                    let s = "";
 | 
			
		||||
| 
						 | 
				
			
			@ -3486,20 +3460,39 @@ export default {
 | 
			
		|||
                    }
 | 
			
		||||
                    return s;
 | 
			
		||||
                },
 | 
			
		||||
 | 
			
		||||
                requiredChanged(newValue,c){
 | 
			
		||||
                    call([{
 | 
			
		||||
                        methodname: 'local_treestudyplan_require_competency',
 | 
			
		||||
                        args: { 'competency_id': c.id,
 | 
			
		||||
                                'item_id': this.item.id,
 | 
			
		||||
                                'required': newValue,
 | 
			
		||||
                                }
 | 
			
		||||
                    }])[0].fail(notification.exception);
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            template: `
 | 
			
		||||
            <table class="r-item-course-grade-details">
 | 
			
		||||
            <table class="t-item-course-competency-list">
 | 
			
		||||
                <tr v-if="value.competencies.length == 0">
 | 
			
		||||
                    <td colspan='2'>{{text.competencies_not_configured}}!
 | 
			
		||||
                    <br><a :href="'/admin/tool/lp/coursecompetencies.php?courseid='+course.id" target='_blank'>{{text.configure_competencies}}</a>
 | 
			
		||||
                    <br><a :href="'/admin/tool/lp/coursecompetencies.php?courseid='+item.course.id" target='_blank'>{{text.configure_competencies}}</a>
 | 
			
		||||
                    </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <template v-else>
 | 
			
		||||
                    <tr class='t-item-course-competency-headers'>
 | 
			
		||||
                        <th>{{text.heading}}</th>
 | 
			
		||||
                        <th></th>
 | 
			
		||||
                        <th>{{text.required}}</th>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                    <tr v-for='c in value.competencies'>
 | 
			
		||||
                        <td><a href='#' v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.title'></span></a></td>
 | 
			
		||||
                        <td v-if="c.details">
 | 
			
		||||
                            <span v-html='c.details'></span>
 | 
			
		||||
                        <td :colspan="(c.details)?1:2"><a href='#' v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.title'></span></a></td>
 | 
			
		||||
                        <td class='details' v-if="c.details">
 | 
			
		||||
                            <a href='#' v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.details'></span></a>
 | 
			
		||||
                        </td>
 | 
			
		||||
                        <td>
 | 
			
		||||
                            <b-form-checkbox inline
 | 
			
		||||
                                @change="requiredChanged($event,c)"
 | 
			
		||||
                                v-model="c.required"
 | 
			
		||||
                            >{{ text.required }}</b-form-checkbox>
 | 
			
		||||
                        </td>
 | 
			
		||||
                        <b-modal :id="'modal-competency-id-'+c.id"
 | 
			
		||||
                            size="lg"
 | 
			
		||||
| 
						 | 
				
			
			@ -3516,14 +3509,24 @@ export default {
 | 
			
		|||
                                    <div><span v-html="pathtags(c)"></span></div>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </template>
 | 
			
		||||
                            <span v-html='c.description'></span>
 | 
			
		||||
                            <table v-if="c.children">
 | 
			
		||||
                                <tr v-for="cc in c.children">
 | 
			
		||||
                                <td><span v-html='cc.displayfield'></span>
 | 
			
		||||
                                </td><td><span v-html='cc.description'></span>
 | 
			
		||||
                                </td>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </table>
 | 
			
		||||
                            <div class="mb-2" v-if="c.description"><span v-html='c.description'></span></div>
 | 
			
		||||
 | 
			
		||||
                            <template v-if="c.rule && c.children">
 | 
			
		||||
                                <div>{{ c.ruleoutcome }} {{ text.when}} <span v-html="c.rule.toLocaleLowerCase()"></span></div>
 | 
			
		||||
                                <table v-if="c.children" class='t-item-course-competency-list'>
 | 
			
		||||
                                    <tr class='t-item-course-competency-headers'>
 | 
			
		||||
                                        <th>{{text.heading}}</th>
 | 
			
		||||
                                        <th></th>
 | 
			
		||||
                                        <th>{{text.required}}</th>
 | 
			
		||||
                                    </tr>
 | 
			
		||||
                                    <tr v-for="cc in c.children">
 | 
			
		||||
                                        <td :colspan="(c.details)?1:2" ><span v-html='cc.title'></span></td>
 | 
			
		||||
                                        <td class='details' v-if="cc.details"><span v-html='cc.details'></span></td>
 | 
			
		||||
                                        <td><span class="text-info">{{ cc.points }} {{ text.points }}</span></td>
 | 
			
		||||
                                        <td><span class="text-danger" v-if='cc.required'>{{ text.required }}</span></td>
 | 
			
		||||
                                    </tr>
 | 
			
		||||
                                </table>
 | 
			
		||||
                            </template>
 | 
			
		||||
                        </b-modal>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                </template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,8 +21,8 @@ export function load_strings(strings){
 | 
			
		|||
        }
 | 
			
		||||
        getstr_func(stringkeys).then(function(str){
 | 
			
		||||
            let i = 0;
 | 
			
		||||
            for(const key in strings[idx]){
 | 
			
		||||
                strings[idx][key] = str[i];
 | 
			
		||||
            for(const handle in strings[idx]){
 | 
			
		||||
                strings[idx][handle] = str[i];
 | 
			
		||||
                i++;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@ use core_competency\course_competency;
 | 
			
		|||
use core_competency\competency;
 | 
			
		||||
use core_competency\api as c_api;
 | 
			
		||||
use core_competency\competency_rule_points;
 | 
			
		||||
use core_competency\evidence;
 | 
			
		||||
use stdClass;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +90,9 @@ class coursecompetencyinfo {
 | 
			
		|||
            "count" => new \external_value(PARAM_INT, 'number of students in stats',VALUE_OPTIONAL),
 | 
			
		||||
            "required" => new \external_value(PARAM_BOOL, 'if required in parent competency rule',VALUE_OPTIONAL),
 | 
			
		||||
            "points" => new \external_value(PARAM_INT, 'number of points in parent competency rule',VALUE_OPTIONAL),
 | 
			
		||||
            "progress" => new \external_value(PARAM_INT, 'number completed child competencies/points',VALUE_OPTIONAL),
 | 
			
		||||
            "count" => new \external_value(PARAM_INT, 'number of child competencies/points required',VALUE_OPTIONAL),
 | 
			
		||||
            "feedback" => new \external_value(PARAM_RAW, 'feedback provided with this competency',VALUE_OPTIONAL),
 | 
			
		||||
        ];
 | 
			
		||||
        if($recurse) {
 | 
			
		||||
            $struct["children"] = new \external_multiple_structure(self::competencyinfo_structure(false),'child competencies',VALUE_OPTIONAL);
 | 
			
		||||
| 
						 | 
				
			
			@ -114,8 +118,8 @@ class coursecompetencyinfo {
 | 
			
		|||
     */
 | 
			
		||||
    public static function user_structure($value = VALUE_REQUIRED) : \external_description {
 | 
			
		||||
        return new \external_single_structure([
 | 
			
		||||
            "progress" => new \external_value(PARAM_INT, 'number completed competencies'),
 | 
			
		||||
            "competencies" => new \external_multiple_structure(self::competencyinfo_structure(), 'competencies'),
 | 
			
		||||
            "progress" => new \external_value(PARAM_INT, 'number completed competencies'),
 | 
			
		||||
            "count" => new \external_value(PARAM_INT, 'number of competencies',VALUE_OPTIONAL),
 | 
			
		||||
        ], 'course completion info', $value);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -194,20 +198,19 @@ class coursecompetencyinfo {
 | 
			
		|||
        $ncourseproficient = 0;
 | 
			
		||||
 | 
			
		||||
        foreach($coursecompetencies as $c) {
 | 
			
		||||
            $ci = $this->competencyinfo_model($c);
 | 
			
		||||
            if(!empty($studentslist)){
 | 
			
		||||
                $stats = $this->proficiency_stats($c,$studentlist);
 | 
			
		||||
                $count += $stats->count;
 | 
			
		||||
                $nproficient += $stats->nproficient;
 | 
			
		||||
                $ncourseproficient += $stats->ncourseproficient;
 | 
			
		||||
            }
 | 
			
		||||
            $ci = $this->competencyinfo_model($c);
 | 
			
		||||
            // Copy proficiency stats to model.
 | 
			
		||||
            foreach ((array)$stats as $key => $value) {
 | 
			
		||||
                $ci[$key] = $value;
 | 
			
		||||
                // Copy proficiency stats to model.
 | 
			
		||||
                foreach ((array)$stats as $key => $value) {
 | 
			
		||||
                    $ci[$key] = $value;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            $ci['required'] = $this->is_required($c);
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            $rule = $c->get_rule_object();
 | 
			
		||||
            $ruleoutcome = $c->get('ruleoutcome');
 | 
			
		||||
            if($rule && $ruleoutcome != competency::OUTCOME_NONE) {
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +226,7 @@ class coursecompetencyinfo {
 | 
			
		|||
                } else {
 | 
			
		||||
                    $outcometag = "none";
 | 
			
		||||
                }
 | 
			
		||||
                $model["ruleoutcome"] = get_string("coursemodulecompetencyoutcome_{$outcometag}","core_competency");
 | 
			
		||||
                $ci["ruleoutcome"] = get_string("coursemodulecompetencyoutcome_{$outcometag}","core_competency");
 | 
			
		||||
                
 | 
			
		||||
                if ($rule instanceof competency_rule_points) {
 | 
			
		||||
                    $ruleconfig = json_decode($ruleconfig);
 | 
			
		||||
| 
						 | 
				
			
			@ -234,9 +237,9 @@ class coursecompetencyinfo {
 | 
			
		|||
                    foreach($ruleconfig->competencies as $cr){
 | 
			
		||||
                        $crlist[$cr->id] = $cr;
 | 
			
		||||
                    }
 | 
			
		||||
                    $model["rule"] = $ruletext . " ({$points} ".get_string("points","core_grades").")";
 | 
			
		||||
                    $ci["rule"] = $ruletext . " ({$points} ".get_string("points","core_grades").")";
 | 
			
		||||
                } else {
 | 
			
		||||
                    $model["rule"] = $ruletext;
 | 
			
		||||
                    $ci["rule"] = $ruletext;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // get one level of children
 | 
			
		||||
| 
						 | 
				
			
			@ -289,10 +292,15 @@ class coursecompetencyinfo {
 | 
			
		|||
            foreach ((array)$p as $key => $value) {
 | 
			
		||||
                $ci[$key] = $value;
 | 
			
		||||
            }
 | 
			
		||||
            $ci['required'] = $this->is_required($c);
 | 
			
		||||
            if ($p->proficient || $p->courseproficient) {
 | 
			
		||||
                $progress += 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Retrieve feedback.
 | 
			
		||||
            $ci["feedback"] = $this->retrievefeedback($c,$userid);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            $rule = $c->get_rule_object();
 | 
			
		||||
            $ruleoutcome = $c->get('ruleoutcome');
 | 
			
		||||
            if($rule && $ruleoutcome != competency::OUTCOME_NONE) {
 | 
			
		||||
| 
						 | 
				
			
			@ -308,7 +316,7 @@ class coursecompetencyinfo {
 | 
			
		|||
                } else {
 | 
			
		||||
                    $outcometag = "none";
 | 
			
		||||
                }
 | 
			
		||||
                $model["ruleoutcome"] = get_string("coursemodulecompetencyoutcome_{$outcometag}","core_competency");
 | 
			
		||||
                $ci["ruleoutcome"] = get_string("coursemodulecompetencyoutcome_{$outcometag}","core_competency");
 | 
			
		||||
                
 | 
			
		||||
                if ($rule instanceof competency_rule_points) {
 | 
			
		||||
                    $ruleconfig = json_decode($ruleconfig);
 | 
			
		||||
| 
						 | 
				
			
			@ -325,16 +333,21 @@ class coursecompetencyinfo {
 | 
			
		|||
                // get one level of children
 | 
			
		||||
                $dids = competency::get_descendants_ids($c);
 | 
			
		||||
                if(count($dids) > 0) {
 | 
			
		||||
                    $dcount = 0;
 | 
			
		||||
                    $dprogress = 0;
 | 
			
		||||
                    $children = [];
 | 
			
		||||
                    foreach($dids as $did) {
 | 
			
		||||
                        $cc = new competency($did);
 | 
			
		||||
                        $cci = $this->competencyinfo_model($cc);
 | 
			
		||||
                        $cp = $p = $this->proficiency($cc,$userid);
 | 
			
		||||
                        // Copy proficiency info to model.
 | 
			
		||||
                        foreach ((array)$cp as $key => $value) {
 | 
			
		||||
                            $cci[$key] = $value;
 | 
			
		||||
                        }
 | 
			
		||||
                        // Retrieve feedback.
 | 
			
		||||
                        $cci["feedback"] = $this->retrievefeedback($cc,$userid);
 | 
			
		||||
 | 
			
		||||
                        if($rule instanceof competency_rule_points) {
 | 
			
		||||
                            $cp = $p = $this->proficiency($cc,$userid);
 | 
			
		||||
                           // Copy proficiency info to model.
 | 
			
		||||
                            foreach ((array)$cp as $key => $value) {
 | 
			
		||||
                                $cci[$key] = $value;
 | 
			
		||||
                            }
 | 
			
		||||
                            if(array_key_exists($did,$crlist)) {
 | 
			
		||||
                                $cr = $crlist[$did];
 | 
			
		||||
                                $cci["points"] = (int) $cr->points;
 | 
			
		||||
| 
						 | 
				
			
			@ -343,17 +356,27 @@ class coursecompetencyinfo {
 | 
			
		|||
                                    $points += (int) $cr->points;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            $dcount += 1;
 | 
			
		||||
                            if ($cp->proficient) {
 | 
			
		||||
                                $dprogress += 1;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        $children[] = $cci;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    $ci["children"] = $children;
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($rule instanceof competency_rule_points) {
 | 
			
		||||
                    $model["rule"] = $ruletext . " ({$points} / {$pointsreq} ".get_string("points","core_grades").")";
 | 
			
		||||
                    $ci["rule"] = $ruletext . " ({$points} / {$pointsreq} ".get_string("points","core_grades").")";
 | 
			
		||||
                    $ci["count"] = $pointsreq;
 | 
			
		||||
                    $ci["progress"] = $points;
 | 
			
		||||
                } else {
 | 
			
		||||
                    $model["rule"] = $ruletext;
 | 
			
		||||
                    $ci["rule"] = $ruletext;
 | 
			
		||||
                    $ci["count"] = $dcount;
 | 
			
		||||
                    $ci["progress"] = $dprogress;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -412,16 +435,47 @@ class coursecompetencyinfo {
 | 
			
		|||
    public function proficiency($competency, $userid) {
 | 
			
		||||
        $scale = $competency->get_scale();
 | 
			
		||||
        $competencyid = $competency->get('id');
 | 
			
		||||
        $uc = c_api::get_user_competency($userid, $competencyid);
 | 
			
		||||
        $ucc = c_api::get_user_competency_in_course($this->course->id,$userid,$competencyid);
 | 
			
		||||
        $r = new \stdClass();
 | 
			
		||||
 | 
			
		||||
        $uc = c_api::get_user_competency($userid, $competencyid);
 | 
			
		||||
        $r->proficient = $uc->get('proficiency');
 | 
			
		||||
        $r->courseproficient = $ucc->get('proficiency');
 | 
			
		||||
        $r->grade = $scale->get_nearest_item($uc->get('grade'));
 | 
			
		||||
        $r->coursegrade = $scale->get_nearest_item($ucc->get('grade'));
 | 
			
		||||
        try {
 | 
			
		||||
            // Only add course grade and proficiency if the competency is included in the course.
 | 
			
		||||
            $ucc = c_api::get_user_competency_in_course($this->course->id,$userid,$competencyid);
 | 
			
		||||
            $r->courseproficient = $ucc->get('proficiency');
 | 
			
		||||
            $r->coursegrade = $scale->get_nearest_item($ucc->get('grade'));
 | 
			
		||||
        } catch (\Exception $x) {}
 | 
			
		||||
        return $r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve course proficiency and overall proficiency for a competency and user
 | 
			
		||||
     *
 | 
			
		||||
     * @param \core_competency\competency $competency
 | 
			
		||||
     * @param int $userid
 | 
			
		||||
     * 
 | 
			
		||||
     * @return stdClass 
 | 
			
		||||
     * 
 | 
			
		||||
     */
 | 
			
		||||
    public function retrievefeedback($competency, $userid) {
 | 
			
		||||
        $competencyid = $competency->get('id');
 | 
			
		||||
        $uc = c_api::get_user_competency($userid, $competencyid);
 | 
			
		||||
 | 
			
		||||
        // Get evidences and sort by creation date (newest first)
 | 
			
		||||
        $evidence = evidence::get_records_for_usercompetency($uc->get('id'),\context_system::instance(),'timecreated', "DESC");
 | 
			
		||||
 | 
			
		||||
        // Get the first valid note and return it;
 | 
			
		||||
        foreach($evidence as $e) {
 | 
			
		||||
            if ( in_array($e->get('action'),[evidence::ACTION_OVERRIDE,evidence::ACTION_COMPLETE] )) {
 | 
			
		||||
                return  $e->get('note');
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Webservice executor to mark competency as required
 | 
			
		||||
     * @param int $competencyid ID of the competency
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -197,15 +197,15 @@ class competency_aggregator extends \local_treestudyplan\aggregator {
 | 
			
		|||
        $limit = $this->cfg()->thresh_completed * $count;
 | 
			
		||||
        $coursefinished = ($course->enddate) ? ($course->enddate < time()) : false;
 | 
			
		||||
 | 
			
		||||
        if ($courseproficient >= $count && $requiredmet >= $requiredcount) {
 | 
			
		||||
        if ($proficient >= $count && $requiredmet >= $requiredcount) {
 | 
			
		||||
            if ($limit < $count) {
 | 
			
		||||
                return completion::EXCELLENT;
 | 
			
		||||
            } else {
 | 
			
		||||
                return completion::COMPLETED;
 | 
			
		||||
            }
 | 
			
		||||
        } else if ($courseproficient > $limit && $requiredmet >= $requiredcount) {
 | 
			
		||||
        } else if ($proficient > $limit && $requiredmet >= $requiredcount) {
 | 
			
		||||
            return completion::COMPLETED;
 | 
			
		||||
        } else if ($courseproficient > 0) {
 | 
			
		||||
        } else if ($proficient > 0) {
 | 
			
		||||
            if ( $this->cfg()->use_failed && $coursefinished) {
 | 
			
		||||
                return completion::FAILED;
 | 
			
		||||
            } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -901,7 +901,7 @@ class studyplanservice extends \external_api {
 | 
			
		|||
     ****************************************/
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parameter description for webservice function include_grade
 | 
			
		||||
     * Parameter description for webservice function require_competency
 | 
			
		||||
     */
 | 
			
		||||
    public static function require_competency_parameters() : \external_function_parameters {
 | 
			
		||||
        return new \external_function_parameters( [
 | 
			
		||||
| 
						 | 
				
			
			@ -912,7 +912,7 @@ class studyplanservice extends \external_api {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return value description for webservice function include_grade
 | 
			
		||||
     * Return value description for webservice function require_competency
 | 
			
		||||
     */
 | 
			
		||||
    public static function require_competency_returns() : \external_description {
 | 
			
		||||
        return success::structure();
 | 
			
		||||
| 
						 | 
				
			
			@ -920,15 +920,14 @@ class studyplanservice extends \external_api {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Mark a gradable item for inclusion in the studyplan
 | 
			
		||||
     * Mark a competency as required for course completion
 | 
			
		||||
     * @param mixed $gradeid Id of gradable
 | 
			
		||||
     * @param mixed $itemid Id of study item
 | 
			
		||||
     * @param bool $include Include grade or not
 | 
			
		||||
     * @param bool $required Mark grade as required or not
 | 
			
		||||
     * @return array Success/Fail model
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    public static function require_competency($competencyid, $itemid, $include, $required = false) {
 | 
			
		||||
    public static function require_competency($competencyid, $itemid, $required) {
 | 
			
		||||
        global $USER;
 | 
			
		||||
        $item = studyitem::find_by_id($itemid);
 | 
			
		||||
        // Find related course and course context.
 | 
			
		||||
| 
						 | 
				
			
			@ -944,7 +943,7 @@ class studyplanservice extends \external_api {
 | 
			
		|||
        // Check correct capabilities.
 | 
			
		||||
        if (has_capability('local/treestudyplan:editstudyplan', $item->context()) ||
 | 
			
		||||
           ($coursecontext && is_enrolled($coursecontext, $USER, 'local/treestudyplan:selectowngradables'))) {
 | 
			
		||||
           return coursecompetencyinfo::require_competency($competencyid, $itemid, $include, $required)->model();
 | 
			
		||||
           return coursecompetencyinfo::require_competency($competencyid, $itemid, $required)->model();
 | 
			
		||||
        } else {
 | 
			
		||||
            return success::fail("Access denied")->model();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1306,6 +1306,22 @@
 | 
			
		|||
    margin-bottom: auto;
 | 
			
		||||
    margin-left: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
.path-local-treestudyplan table.t-item-course-competency-list,
 | 
			
		||||
.features-treestudyplan table.t-item-course-competency-list {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.path-local-treestudyplan table.t-item-course-competency-list td,
 | 
			
		||||
.features-treestudyplan table.t-item-course-competency-list td {
 | 
			
		||||
    padding-right: 1em;
 | 
			
		||||
}
 | 
			
		||||
.path-local-treestudyplan table.t-item-course-competency-list td.details,
 | 
			
		||||
.features-treestudyplan table.t-item-course-competency-list td.details {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.path-local-treestudyplan table.r-item-course-competency-list td,
 | 
			
		||||
.features-treestudyplan table.r-item-course-competency-list td {
 | 
			
		||||
    padding-right: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.path-local-treestudyplan .card.s-studyplan-card,
 | 
			
		||||
.features-treestudyplan .card.s-studyplan-card {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,6 +177,9 @@ $string["condition_any"] = 'One or more entries need to be completed';
 | 
			
		|||
$string["courses"] = 'Courses';
 | 
			
		||||
$string["select_grades"] = 'Grades included in report';
 | 
			
		||||
 | 
			
		||||
$string["configure_competency"] = "Configure course competencies";
 | 
			
		||||
$string["competency_not_configured"] = "Course competencies have not yet been configured.";
 | 
			
		||||
 | 
			
		||||
$string["configure_completion"] = "Configure course completion";
 | 
			
		||||
$string["completion_not_configured"] = "Course completion has not yet been configured.";
 | 
			
		||||
$string["completion_failed"] = "Failed";
 | 
			
		||||
| 
						 | 
				
			
			@ -242,6 +245,7 @@ $string["allgraded"] = 'All graded';
 | 
			
		|||
$string["unsubmitted"] = 'No submission';
 | 
			
		||||
$string["nogrades"] = 'No grades';
 | 
			
		||||
$string["unknown"] = 'Grading status unknown';
 | 
			
		||||
$string["when"] = "when";
 | 
			
		||||
 | 
			
		||||
$string["selectstudent_btn"] = "View student plans";
 | 
			
		||||
$string["selectstudent"] = "Choose student";
 | 
			
		||||
| 
						 | 
				
			
			@ -299,9 +303,14 @@ $string["settingdesc_competency_thresh_completed"] = 'Minimum percentage of prof
 | 
			
		|||
$string["setting_competency_support_failed"] = 'Support "Failed" result';
 | 
			
		||||
$string["settingdesc_competency_support_failed"] = 'When the course end date has passed, mark course as "Failed" instead of "Progress"';
 | 
			
		||||
 | 
			
		||||
$string["grade_include"] = "Include";
 | 
			
		||||
$string["grade_require"] = "Require";
 | 
			
		||||
$string["required_goal"] = "Required outcome";
 | 
			
		||||
$string["grade_include"] = 'Include';
 | 
			
		||||
$string["grade_require"] = 'Require';
 | 
			
		||||
$string["required_goal"] = 'Required outcome';
 | 
			
		||||
$string["required"] = 'Required';
 | 
			
		||||
$string["competency_heading"] = 'Competency';
 | 
			
		||||
$string["competency_details"] = 'Details';
 | 
			
		||||
$string["results"] = 'Results';
 | 
			
		||||
$string["unrated"] = 'Unrated';
 | 
			
		||||
 | 
			
		||||
$string["advanced_tools"] = 'Advanced';
 | 
			
		||||
$string["confirm_cancel"] = 'Cancel';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -174,6 +174,9 @@ $string["condition_any"] = 'Minimaal één onderdeel moet afgerond zijn';
 | 
			
		|||
$string["courses"] = 'Cursussen';
 | 
			
		||||
$string["select_grades"] = 'Resultaten die meetellen';
 | 
			
		||||
 | 
			
		||||
$string["configure_competency"] = "Cursuscompetenties instellen";
 | 
			
		||||
$string["competency_not_configured"] = "De cursuscompetenties zijn nog niet ingesteld.";
 | 
			
		||||
 | 
			
		||||
$string["configure_completion"] = "Voltooiing instellen";
 | 
			
		||||
$string["completion_not_configured"] = "De cursusvoltooiing is nog niet ingesteld.";
 | 
			
		||||
$string["completion_failed"] = "Onvoldoende";
 | 
			
		||||
| 
						 | 
				
			
			@ -239,6 +242,7 @@ $string["allgraded"] = 'Alles beoordeeld';
 | 
			
		|||
$string["unsubmitted"] = 'Geen inzendingen';
 | 
			
		||||
$string["nogrades"] = 'Geen items';
 | 
			
		||||
$string["unknown"] = 'Beoordelingen onbekend';
 | 
			
		||||
$string["when"] = "zodra";
 | 
			
		||||
 | 
			
		||||
$string["selectstudent_btn"] = "Bekijk studentenvoortgang";
 | 
			
		||||
$string["selectstudent"] = "Kies een student";
 | 
			
		||||
| 
						 | 
				
			
			@ -298,9 +302,14 @@ $string["settingdesc_competency_thresh_completed"] = 'Minimumpercentage behaalde
 | 
			
		|||
$string["setting_competency_support_failed"] = 'Onvoldoende ingeschakeld';
 | 
			
		||||
$string["settingdesc_competency_support_failed"] = 'Vink aan om "Onvoldoende" weer te kunnen geven als eind resultaat voor een cursus';
 | 
			
		||||
 | 
			
		||||
$string["grade_include"] = "Doel";
 | 
			
		||||
$string["grade_require"] = "Verplicht";
 | 
			
		||||
$string["required_goal"] = "Verplicht leerdoel";
 | 
			
		||||
$string["grade_include"] = 'Doel';
 | 
			
		||||
$string["grade_require"] = 'Verplicht';
 | 
			
		||||
$string["required_goal"] = 'Verplicht leerdoel';
 | 
			
		||||
$string["required"] = 'Verplicht';
 | 
			
		||||
$string["competency_heading"] = 'Competentie';
 | 
			
		||||
$string["competency_details"] = 'Details';
 | 
			
		||||
$string["results"] = 'Resultaten';
 | 
			
		||||
$string["unrated"] = 'Niet beoordeeld';
 | 
			
		||||
 | 
			
		||||
$string["advanced_tools"] = 'Geavanceerd';
 | 
			
		||||
$string["confirm_cancel"] = 'Annuleren';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1118,4 +1118,23 @@
 | 
			
		|||
        margin-bottom: auto;
 | 
			
		||||
        margin-left: 0.5em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    table.t-item-course-competency-list {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        td {
 | 
			
		||||
            padding-right: 1em;
 | 
			
		||||
        }
 | 
			
		||||
        td.details {
 | 
			
		||||
            width: 100%;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    table.r-item-course-competency-list {
 | 
			
		||||
        td {
 | 
			
		||||
            padding-right: 1em;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								styles.css
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								styles.css
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1306,6 +1306,22 @@
 | 
			
		|||
    margin-bottom: auto;
 | 
			
		||||
    margin-left: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
.path-local-treestudyplan table.t-item-course-competency-list,
 | 
			
		||||
.features-treestudyplan table.t-item-course-competency-list {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.path-local-treestudyplan table.t-item-course-competency-list td,
 | 
			
		||||
.features-treestudyplan table.t-item-course-competency-list td {
 | 
			
		||||
    padding-right: 1em;
 | 
			
		||||
}
 | 
			
		||||
.path-local-treestudyplan table.t-item-course-competency-list td.details,
 | 
			
		||||
.features-treestudyplan table.t-item-course-competency-list td.details {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
}
 | 
			
		||||
.path-local-treestudyplan table.r-item-course-competency-list td,
 | 
			
		||||
.features-treestudyplan table.r-item-course-competency-list td {
 | 
			
		||||
    padding-right: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.path-local-treestudyplan .card.s-studyplan-card,
 | 
			
		||||
.features-treestudyplan .card.s-studyplan-card {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Reference in a new issue