Skip to content

Commit

Permalink
New Functions: tag-search, adjust node position, dark mode, custom node
Browse files Browse the repository at this point in the history
  • Loading branch information
WunderJacob committed Nov 23, 2023
1 parent 737f7d6 commit 1b7259b
Show file tree
Hide file tree
Showing 14 changed files with 379 additions and 190 deletions.
88 changes: 77 additions & 11 deletions amd/src/app-lazy.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion classes/admin_setting_course_tags.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function validate($data) {
foreach ($usedtags as $usedtag) {
if (!in_array($usedtag, $tagsarray)) {
if ($usedtag != '') {
$notfoundtags = 'Please watch for whitespaces and do not end with a comma';
$notfoundtags = get_string('warning_empty_space', 'local_adele');
} else {
$notfoundtags .= $usedtag . ',';
}
Expand Down
2 changes: 2 additions & 0 deletions classes/external/get_availablecourses.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ public static function execute_returns(): external_multiple_structure {
'id' => new external_value(PARAM_INT, 'Item id'),
'fullname' => new external_value(PARAM_TEXT, 'Historyid id'),
'shortname' => new external_value(PARAM_TEXT, 'Item name'),
'category' => new external_value(PARAM_TEXT, 'Category level'),
's1' => new external_value(PARAM_TEXT, 'Item tags'),
]
)
);
Expand Down
168 changes: 90 additions & 78 deletions classes/learning_path_courses.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,97 +52,43 @@ public static function get_availablecourses() {
*/
public static function buildsqlquery() {
global $DB, $USER;
$where = "";
$configadele = get_config('local_adele');

// Search courses that are tagged with the specified tag.
$configtags['OR'] = explode(',', str_replace(' ', '', $configadele->includetags));
$configtags['AND'] = explode(',', str_replace(' ', '', $configadele->excludetags));

$params = [];
$usersql = ' ';

if ($configtags['OR'][0] != null || $configtags['AND'][0] != null || $configadele->catfilter[0] != null) {
$where = "JOIN {context} ctx ON c.id = ctx.instanceid AND ctx.contextlevel = :contextcourse
WHERE c.id IN (SELECT t.itemid
FROM {tag_instance} t WHERE (";
$concat = false;

// Filter according to the tags.
if ($configtags['OR'][0] != null || $configtags['AND'][0] != null) {
if ($configtags['OR'][0] != null && $configtags['AND'][0] != null) {
$concat = true;
}
$indexparam = 0;
foreach ($configtags as $operator => $tags) {
if (!empty($tags[0])) {
$tagscount = count($tags);
foreach ($tags as $index => $tag) {
$tag = (array) $DB->get_record('tag', ['name' => $tag], 'id, name');
$params['tag'. $indexparam] = $tag['id'];
$where .= "t.tagid";
$where .= $operator == 'OR' ? ' = ' : ' != ';
$where .= ":tag" . $indexparam;
if ($index + 1 < $tagscount) {
$where .= ' ' . $operator .' ';
} else {
$where .= ")";
};
$indexparam += 1;
}
if ($concat) {
$where .= " AND (";
$concat = false;
}
}
}
}
$selectagg = $DB->sql_group_concat('tag.name') . ' as s1';
$userquery = '';
$select = "SELECT s1.*
FROM (
SELECT ti.itemid AS id, c.fullname, c.shortname, c.category, " . $selectagg . "
FROM m_tag_instance ti
LEFT JOIN {tag} tag ON ti.tagid = tag.id
LEFT JOIN {course} c ON ti.itemid = c.id
%USERQUERY%
WHERE ti.itemtype = 'course'
GROUP BY ti.itemid, c.id
) AS s1 %WHEREQUERY%
";

// Filter according to the category level.
if ($configadele->catfilter[0] != null ) {
$configcategories = explode(',', str_replace(' ', '', $configadele->catfilter));
$sqlcategories = "SELECT id FROM {course_categories} WHERE ";
foreach ($configcategories as $index => $configcategory) {
$sqlcategories .= "path LIKE '%/" . $configcategory . "/%'";
if ($index + 1 < count($configcategories)) {
$sqlcategories .= ' OR ';
}
}
$categorylist = $DB->get_records_sql($sqlcategories);
foreach ($categorylist as $category) {
$configcategories[] = $category->id;
}
if (!empty($configcategories) ) {
if ($concat) {
$where .= ' AND (';
}
foreach ($configcategories as $catindex => $catid) {
$where .= 'category = :catid' . $catindex;
$params['catid' . $catindex] = $catid;
if ($catindex + 1 < count($configcategories)) {
$where .= ' OR ';
}
}
$where .= ')';
}
}
$configadele = get_config('local_adele');

$where .= ")";
}
// Search courses that are tagged with the specified tag.
$configtags['include'] = explode(',', str_replace(' ', '', $configadele->includetags));
$configtags['exclude'] = explode(',', str_replace(' ', '', $configadele->excludetags));
$configtags['category'] = self::get_categories($configadele->catfilter);
$whereparamsquery = self::build_where_query($configtags);

// Filter according to select button.
if ($configadele->selectconfig != null && $configadele->selectconfig == 'only_subscribed') {
global $USER;
$usersql = "JOIN (SELECT DISTINCT e.courseid
$userquery = "JOIN (SELECT DISTINCT e.courseid
FROM {enrol} e
JOIN {user_enrolments} ue ON
(ue.enrolid = e.id AND ue.userid = :userid)
) en ON (en.courseid = c.id) ";

$params["userid"] = $USER->id;
$whereparamsquery['params']["userid"] = $USER->id;
}
return self::get_course_records($where, $params, $usersql);

$select = str_replace( ['%USERQUERY%', '%WHEREQUERY%'], [$userquery, $whereparamsquery['wherequery']], $select);
return $DB->get_records_sql($select,
['contextcourse' => CONTEXT_COURSE] + $whereparamsquery['params']);
}

/**
Expand All @@ -164,4 +110,70 @@ protected static function get_course_records($whereclause, $params, $usersql) {
['contextcourse' => CONTEXT_COURSE] + $params);
return $list;
}

/**
* Build sql query with config filters.
* @param string $categories
* @return array
*/
protected static function get_categories($categories) {
global $DB;
// Filter according to the category level.
$configcategories = explode(',', str_replace(' ', '', $categories));
$sqlcategories = "SELECT id FROM {course_categories} WHERE ";
foreach ($configcategories as $index => $configcategory) {
$sqlcategories .= "path LIKE '%/" . $configcategory . "/%'";
if ($index + 1 < count($configcategories)) {
$sqlcategories .= ' OR ';
}
}
$categorylist = $DB->get_records_sql($sqlcategories);
foreach ($categorylist as $category) {
$configcategories[] = $category->id;
}
return $configcategories;
}
/**
* Build sql query with config filters.
* @param array $configfilter
* @return array
*/
protected static function build_where_query($configfilters) { $wherequeries = [];
$params = [];
$wherequery = '';
foreach ($configfilters as $index => $configfilter) {
$tagquery = "(s1.tags OPERATOR ':TAG' OR s1.tags OPERATOR ':TAG,%' OR s1.tags
OPERATOR '%,:TAG' OR s1.tags OPERATOR '%,:TAG,%')";
if (!empty($configfilter[0])) {
$indexfilter = 0;
$filtercount = count($configfilter);
if ($index == 'category') {
$wherequery .= '(';
foreach ($configfilter as $filter) {
$wherequery .= 's1.category = :' . $index . $indexfilter;
$params[$index . $indexfilter] = $filter;
if ($indexfilter + 1 < $filtercount) {
$wherequery .= ' OR ';
}
$indexfilter += 1;
}
$wherequery .= ")";
} else {
$operator = $index == 'include' ? 'LIKE' : 'NOT LIKE';
foreach ($configfilter as $filter) {
$wherequery .= str_replace(['OPERATOR', ':TAG'], [$operator, $filter], $tagquery);
$indexfilter += 1;
}
}
}
}
if ($wherequery != '') {
$wherequery = 'WHERE ' . str_replace(')(', ') AND (', $wherequery);
}
return [
'wherequery' => $wherequery,
'params' => $params
];

}
}
38 changes: 23 additions & 15 deletions lang/en/local_adele.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

// Vue component route not found.
$string['route_not_found_site_name'] = 'Error: Page (route) not found!';
$string['route_not_found'] = 'Page was not found. Please consider going back and and trying it again.';
$string['route_not_found'] = 'Page was not found. Please consider going back and trying it again.';

// Vue component learning goal edit.
$string['learninggoals_edit_site_name'] = 'adele learning goals';
Expand Down Expand Up @@ -68,24 +68,16 @@
$string['save'] = 'Save';
$string['cancel'] = 'Cancel';

// Tabs.
$string['thinkingskill'] = 'Thinking Skill';
$string['content'] = 'Content';
$string['resources'] = 'Resources';
$string['products'] = 'Products';
$string['groups'] = 'Groups';

// Words.
$string['prethinkingskill'] = 'Students will';
$string['clicktoedit'] = '[click to edit]';
$string['preresource'] = 'using';
$string['preproduct'] = 'and create';
$string['pregroup'] = 'in groups of';

// Button strings.
$string['btnadele'] = 'Learning Paths';
$string['btnbacktooverview'] = 'Going back to overview';
$string['btncreatecourse'] = 'Go to page and create a course';
$string['btnsave'] = 'save';
$string['btncancel'] = 'cancel';
$string['btnupdate_positions'] = 'update positions';
$string['btntoggle'] = 'change view';



// From Strings.
$string['fromlearningtitel'] = 'Learning Path Tiel';
Expand All @@ -110,3 +102,19 @@
$string['categories'] = 'Define category level';
$string['categories_desc'] = 'Define course-level should be included';
$string['tag_invalid'] = 'Following tags were not found: {$a}';
$string['warning_empty_space'] = 'Please watch for whitespaces and do not end with a comma';
$string['settings_only_subscribed'] = 'Only courses the teacher is subscribed to.';
$string['settings_all_courses'] = 'All courses meeting the other criteria.';


// Notifications.
$string['title_duplicate'] = 'Learning Path duplicated';
$string['description_duplicate'] = 'You have duplicated the Learning Path!';
$string['title_delete'] = 'Learning Path deleted';
$string['description_delete'] = 'You have deleted the Learning Path!';
$string['title_save'] = 'Learning Path saved/updated';
$string['description_save'] = 'You have saved/updated the Learning Path!';

// Node Strings.
$string['node_coursefullname'] = 'Full Coursename:';
$string['node_courseshortname'] = 'Short Coursename:';
4 changes: 2 additions & 2 deletions settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
get_string('activefilter_desc', $componentname),
'only_subscribed',
[
'only_subscribed' => 'Only courses the theacher is subscribed to.',
'all_courses' => 'All courses meeting the other criterias.',
'only_subscribed' => get_string('settings_only_subscribed', $componentname),
'all_courses' => get_string('settings_all_courses', $componentname),
]));

// Included tags.
Expand Down
6 changes: 0 additions & 6 deletions vue3/components/flowchart/ConnectionLine.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script setup>
import { connectionExists, getBezierPath, useVueFlow } from '@vue-flow/core'
import { computed, reactive, ref, watch } from 'vue'
import { notify } from "@kyvg/vue3-notification";
const props = defineProps({
sourceX: {
Expand Down Expand Up @@ -143,11 +142,6 @@ const strokeColor = computed(() => {
return '#222'
})
// Add the onConnectionStart method
const onConnectionStart = (startHandle) => {
closest.startHandle = startHandle
}
</script>
<template>
Expand Down
34 changes: 24 additions & 10 deletions vue3/components/flowchart/Controls.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<script setup>
import { Panel, useVueFlow } from '@vue-flow/core'
import { Panel, useVueFlow, isNode } from '@vue-flow/core'
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
import { watch, onUnmounted } from 'vue';
import { watch } from 'vue';
import { notify } from "@kyvg/vue3-notification";
const store = useStore();
const router = useRouter();
Expand All @@ -22,7 +21,6 @@ const flowchart = (flow) => {
}
};
let stopNodeWatcher;
const emit = defineEmits();
const emitNodeCount = (count) => {
emit('node-count-changed', count);
Expand Down Expand Up @@ -55,8 +53,6 @@ if (store.state.learninggoal[0].json.tree != undefined) {
const onSave = () => {
let action = props.learninggoal.id == 0 ? 'saved' : 'edited';
let obj = {};
obj['tree'] = toObject();
obj = JSON.stringify(obj);
Expand All @@ -74,8 +70,8 @@ const onSave = () => {
window.scrollTo(0,0);
notify({
title: "Learning Path " + action,
text: "You have " + action + " the Learning Path!",
title: store.state.strings.title_save,
text: store.state.strings.description_save,
type: 'success'
});
Expand All @@ -87,12 +83,30 @@ const onCancel = () => {
router.push({name: 'learninggoals-edit-overview'});
};
function updatePos() {
let elements = toObject();
elements.nodes.forEach((el) => {
if (isNode(el)) {
el.position = {
x: Math.ceil(el.position.x / 10) * 10,
y: Math.ceil(el.position.y / 10) * 10,
}
}
})
flowchart(elements)
}
function toggleClass() {
emit('change-class');
}
</script>

<template>
<Panel position="bottom-center" class="save-restore-controls">
<button class="btn btn-primary" @click="onSave">save</button>
<button class="btn btn-secondary" @click="onCancel">cancel</button>
<button class="btn btn-primary" @click="onSave">{{store.state.strings.save}}</button>
<button class="btn btn-secondary" @click="onCancel">{{store.state.strings.btncancel}}</button>
<button class="btn btn-info" @click="updatePos">{{store.state.strings.btnupdate_positions}}</button>
<button class="btn btn-warning" @click="toggleClass">{{store.state.strings.btntoggle}}</button>
</Panel>
</template>
Loading

0 comments on commit 1b7259b

Please sign in to comment.