diff --git a/app/controllers/search/courses.php b/app/controllers/search/courses.php index 9e0b45d6e31adfa3df193efccc5487c99501a63d..50a348066fa9dad1f5333c435729b2b6fe4d3cc8 100644 --- a/app/controllers/search/courses.php +++ b/app/controllers/search/courses.php @@ -28,10 +28,6 @@ class Search_CoursesController extends AuthenticatedController PageLayout::setHelpKeyword('Basis.VeranstaltungenAbonnieren'); $this->type = Request::option('type', 'semtree'); - $this->show_as = Request::option('show_as', 'list'); - if (!in_array($this->show_as, ['list', 'table'])) { - $this->show_as = 'list'; - } $this->semester = Request::option('semester', Semester::findCurrent()->id); $this->semClass = Request::int('semclass', 0); $this->search = Request::get('search', ''); @@ -111,16 +107,5 @@ class Search_CoursesController extends AuthenticatedController $sidebar->addWidget(new VueWidget('search-widget')); $sidebar->addWidget(new VueWidget('export-widget')); - - $views = new ViewsWidget(); - $views->addLink( - _('Als Liste'), - $this->url_for('search/courses', array_merge($params, ['show_as' => 'list'])) - )->setActive($this->show_as === 'list'); - $views->addLink( - _('Als Tabelle'), - $this->url_for('search/courses', array_merge($params, ['show_as' => 'table'])) - )->setActive($this->show_as === 'table'); - $sidebar->addWidget($views); } } diff --git a/app/views/search/courses/index.php b/app/views/search/courses/index.php index 500c31e7f69d808dfe18fdaeceab04a16ba03744..c6f490506018972d0765c56676e34fb9b73d6835 100644 --- a/app/views/search/courses/index.php +++ b/app/views/search/courses/index.php @@ -1,15 +1,11 @@ <?php /** * @var String $startId - * @var String $show_as - * @var String $treeTitle - * @var String $breadcrumIcon - * @var String $semester - * @var String $semClass + * @var String $nodeClass */ ?> <div data-studip-tree> - <studip-tree start-id="<?= htmlReady($startId) ?>" view-type="<?= htmlReady($show_as) ?>" :visible-children-only="true" + <studip-tree start-id="<?= htmlReady($startId) ?>" view-type="list" :visible-children-only="true" title="<?= htmlReady($treeTitle) ?>" breadcrumb-icon="<?= htmlReady($breadcrumbIcon) ?>" :with-search="true" :with-export="true" :with-courses="true" semester="<?= htmlReady($semester) ?>" :sem-class="<?= htmlReady($semClass) ?>" :with-export="true"></studip-tree> diff --git a/lib/classes/JsonApi/Routes/Tree/CourseInfoOfTreeNode.php b/lib/classes/JsonApi/Routes/Tree/CourseInfoOfTreeNode.php index e684c40301b2e26d4a3c9e109129229de257753f..283593150cf5c0c4ec8d3fb5cc0ae2555b9ff2d4 100644 --- a/lib/classes/JsonApi/Routes/Tree/CourseInfoOfTreeNode.php +++ b/lib/classes/JsonApi/Routes/Tree/CourseInfoOfTreeNode.php @@ -32,7 +32,8 @@ class CourseinfoOfTreeNode extends NonJsonApiController $filters = $this->getContextFilters($request); $info = [ - 'courses' => (int) $node->countCourses($filters['semester'], $filters['semclass'], true) + 'courses' => (int) $node->countCourses($filters['semester'], $filters['semclass']), + 'allCourses' => (int) $node->countCourses($filters['semester'], $filters['semclass'], true) ]; $response->getBody()->write(json_encode($info)); diff --git a/lib/models/StudipStudyArea.class.php b/lib/models/StudipStudyArea.class.php index 2d13b186eff39112472337fe562899f9a2649c9d..444ca21291237d152b8aa2e2824c2f96675732c5 100644 --- a/lib/models/StudipStudyArea.class.php +++ b/lib/models/StudipStudyArea.class.php @@ -494,7 +494,7 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode OR sc.`semester_id` IS NULL )"; $parameters = [ - 'ids' => $with_children ? array_merge([$this->id], $this->getDescendantIds()) : [$this->id], + 'ids' => $with_children ? $this->getDescendantIds() : [$this->id], 'semester' => $semester_id ]; } else { @@ -502,7 +502,7 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode FROM `seminar_sem_tree` t JOIN `seminare` s ON (s.`Seminar_id` = t.`seminar_id`) WHERE `sem_tree_id` IN (:ids)"; - $parameters = ['ids' => $with_children ? array_merge([$this->id], $this->getDescendantIds()) : [$this->id]]; + $parameters = ['ids' => $with_children ? $this->getDescendantIds() : [$this->id]]; } if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) { diff --git a/resources/assets/stylesheets/scss/loading-skeleton.scss b/resources/assets/stylesheets/scss/loading-skeleton.scss deleted file mode 100644 index 480255fe502110970ee3daf54dec1768addf3240..0000000000000000000000000000000000000000 --- a/resources/assets/stylesheets/scss/loading-skeleton.scss +++ /dev/null @@ -1,5 +0,0 @@ -.studip-loading-skeleton { - background-color: var(--light-gray-color-20); - height: 1em; - width: 100%; -} diff --git a/resources/assets/stylesheets/scss/tree.scss b/resources/assets/stylesheets/scss/tree.scss index 1d700f92eb5d1b29b85151f055abd167e56bae47..dbad68b1bc507c14dacc893b93662e8631eb6e84 100644 --- a/resources/assets/stylesheets/scss/tree.scss +++ b/resources/assets/stylesheets/scss/tree.scss @@ -271,8 +271,8 @@ $tree-outline: 1px solid var(--light-gray-color-40); background: var(--dark-gray-color-5); border: solid thin var(--light-gray-color-40); display: flex; - min-height: 130px; - padding: 5px 10px; + height: 130px; + padding: 10px; /* Handle for drag&drop */ .drag-handle { @@ -284,17 +284,11 @@ $tree-outline: 1px solid var(--light-gray-color-40); flex-direction: column; padding: 10px; text-align: left; - width: 100%; .studip-tree-child-title { font-size: 1.1em; font-weight: bold; } - - .studip-tree-child-description { - color: var(--black); - font-size: 0.9em; - } } &:hover { diff --git a/resources/assets/stylesheets/studip.scss b/resources/assets/stylesheets/studip.scss index 9cc80c6e1133de1092aa2323922bdcd54cffbbf3..467c50243ee266c2df38c91eb3c0e993688da2a2 100644 --- a/resources/assets/stylesheets/studip.scss +++ b/resources/assets/stylesheets/studip.scss @@ -58,7 +58,6 @@ @import "scss/globalsearch"; @import "scss/links"; @import "scss/lists"; -@import "scss/loading-skeleton.scss"; @import "scss/messages"; @import "scss/my_courses"; @import "scss/mvv"; diff --git a/resources/vue/components/StudipLoadingSkeleton.vue b/resources/vue/components/StudipLoadingSkeleton.vue deleted file mode 100644 index 90b973397032cfb35556dea67c5ed76377d73c76..0000000000000000000000000000000000000000 --- a/resources/vue/components/StudipLoadingSkeleton.vue +++ /dev/null @@ -1,9 +0,0 @@ -<template> - <div class="studip-loading-skeleton"></div> -</template> - -<script> -export default { - name: 'StudipLoadingSkeleton' -} -</script> diff --git a/resources/vue/components/tree/StudipTreeList.vue b/resources/vue/components/tree/StudipTreeList.vue index 4ba08bcbb81200e3751530c7c3c32e8fda65d3e9..b607e02197a1bff868fe4a3ce73a0866055b7e56 100644 --- a/resources/vue/components/tree/StudipTreeList.vue +++ b/resources/vue/components/tree/StudipTreeList.vue @@ -62,8 +62,8 @@ </span> <span v-if="withCourses && subLevelsCourses > 0 && !showingAllCourses"> <button type="button" @click="showAllCourses(true)" - :title="$gettext('Veranstaltungen auf Unterebenen anzeigen')"> - {{ $gettext('Veranstaltungen auf Unterebenen anzeigen') }} + :title="$gettext('Veranstaltungen auf allen Unterebenen anzeigen')"> + {{ $gettext('Veranstaltungen auf allen Unterebenen anzeigen') }} </button> </span> </section> @@ -74,15 +74,6 @@ <col> </colgroup> <thead> - <tr v-if="totalCourseCount > limit"> - <td colspan="2"> - <studip-pagination :items-per-page="limit" - :total-items="totalCourseCount" - :current-offset="offset" - @updateOffset="updateOffset" - /> - </td> - </tr> <tr> <th>{{ $gettext('Name') }}</th> <th>{{ $gettext('Information') }}</th> @@ -107,17 +98,6 @@ </td> </tr> </tbody> - <tfoot v-if="totalCourseCount > limit"> - <tr> - <td colspan="2"> - <studip-pagination :items-per-page="limit" - :total-items="totalCourseCount" - :current-offset="offset" - @updateOffset="updateOffset" - /> - </td> - </tr> - </tfoot> </table> <MountingPortal v-if="showExport" mountTo="#export-widget" name="sidebar-export"> <tree-export-widget v-if="courses.length > 0" @@ -138,14 +118,13 @@ import TreeBreadcrumb from './TreeBreadcrumb.vue'; import TreeNodeTile from './TreeNodeTile.vue'; import StudipProgressIndicator from '../StudipProgressIndicator.vue'; import TreeCourseDetails from './TreeCourseDetails.vue'; -import AssignLinkWidget from './AssignLinkWidget.vue'; -import StudipPagination from '../StudipPagination.vue'; +import AssignLinkWidget from "./AssignLinkWidget.vue"; export default { name: 'StudipTreeList', components: { draggable, StudipProgressIndicator, TreeExportWidget, TreeBreadcrumb, TreeNodeTile, TreeCourseDetails, - AssignLinkWidget, StudipPagination + AssignLinkWidget }, mixins: [ TreeMixin ], props: { @@ -246,10 +225,8 @@ export default { }); if (this.withCourses) { - this.getNodeCourses(node, this.offset, this.semester, this.semClass, '', false) + this.getNodeCourses(node, this.semester, this.semClass, '', false) .then(courses => { - this.totalCourseCount = courses.data.meta.page.total; - this.offset = Math.ceil(courses.data.meta.page.offset / this.limit); this.courses = courses.data.data; }); } @@ -311,10 +288,8 @@ export default { } }, showAllCourses(state) { - this.getNodeCourses(this.currentNode, this.offset, this.semester, this.semClass, '', state) + this.getNodeCourses(this.currentNode, this.semester, this.semClass, '', state) .then(courses => { - this.totalCourseCount = courses.data.meta.page.total; - this.offset = Math.ceil(courses.data.meta.page.offset / this.limit); this.courses = courses.data.data; this.showingAllCourses = state; }); @@ -334,10 +309,8 @@ export default { }); if (this.withCourses) { - this.getNodeCourses(this.currentNode, 0, this.semester, this.semClass) + this.getNodeCourses(this.currentNode, this.semester, this.semClass) .then(courses => { - this.totalCourseCount = courses.data.meta.page.total; - this.offset = 0; this.courses = courses.data.data; }); } diff --git a/resources/vue/components/tree/StudipTreeNode.vue b/resources/vue/components/tree/StudipTreeNode.vue index 2b5676e24a38455201ff5b0c6a898036f231b1ba..39f696ccc14e12480701eb2501a71b34cffacf4a 100644 --- a/resources/vue/components/tree/StudipTreeNode.vue +++ b/resources/vue/components/tree/StudipTreeNode.vue @@ -175,7 +175,7 @@ export default { } if (ids.length > 0) { - this.getNodeCourses(this.node, 0, 'all', 0, '', false, ids) + this.getNodeCourses(this.node, 'all', 0, '', false, ids) .then(response => { // None of the given courses are assigned here. if (response.data.data.length === 0) { diff --git a/resources/vue/components/tree/StudipTreeTable.vue b/resources/vue/components/tree/StudipTreeTable.vue index 03a9d7b60e9ac64c2263d4da5b609e1717ce0495..585acd426046c1cda90ac862d5354bf105c36a96 100644 --- a/resources/vue/components/tree/StudipTreeTable.vue +++ b/resources/vue/components/tree/StudipTreeTable.vue @@ -35,8 +35,8 @@ </template> <span v-if="withCourses && subLevelsCourses > 0 && !showingAllCourses"> <button type="button" @click="showAllCourses(true)" - :title="$gettext('Veranstaltungen auf Unterebenen anzeigen')"> - {{ $gettext('Veranstaltungen auf Unterebenen anzeigen') }} + :title="$gettext('Veranstaltungen auf allen Unterebenen anzeigen')"> + {{ $gettext('Veranstaltungen auf allen Unterebenen anzeigen') }} </button> </span> </section> @@ -57,15 +57,6 @@ <col style="width: 40%"> </colgroup> <thead> - <tr v-if="totalCourseCount > limit"> - <td colspan="4"> - <studip-pagination :items-per-page="limit" - :total-items="totalCourseCount" - :current-offset="offset" - @updateOffset="updateOffset" - /> - </td> - </tr> <tr> <th></th> <th>{{ $gettext('Typ') }}</th> @@ -98,11 +89,8 @@ </a> </td> <td> - <tree-node-course-info v-if="node.attributes.ancestors.length > 2" - :node="child" - :semester="semester" - :sem-class="semClass" - ></tree-node-course-info> + <tree-node-course-info :node="child" :semester="semester" + :sem-class="semClass"></tree-node-course-info> </td> </tr> <tr v-for="(course) in courses" :key="course.id" class="studip-tree-child studip-tree-course"> @@ -126,17 +114,6 @@ </td> </tr> </draggable> - <tfoot v-if="totalCourseCount > limit"> - <tr> - <td colspan="4"> - <studip-pagination :items-per-page="limit" - :total-items="totalCourseCount" - :current-offset="offset" - @updateOffset="updateOffset" - /> - </td> - </tr> - </tfoot> </table> <MountingPortal v-if="showExport" mountTo="#export-widget" name="sidebar-export"> <tree-export-widget v-if="courses.length > 0" :title="$gettext('Download des Ergebnisses')" :url="exportUrl()" @@ -265,10 +242,8 @@ export default { if (this.withCourses) { - this.getNodeCourses(node, this.offset, this.semester, this.semClass, '', false) + this.getNodeCourses(node, this.semester, this.semClass, '', false) .then(response => { - this.totalCourseCount = response.data.meta.page.total; - this.offset = Math.ceil(response.data.meta.page.offset / this.limit); this.courses = response.data.data; }); } @@ -330,10 +305,8 @@ export default { } }, showAllCourses(state) { - this.getNodeCourses(this.currentNode, this.offset, this.semester, this.semClass, '', state) + this.getNodeCourses(this.currentNode, this.semester, this.semClass, '', state) .then(courses => { - this.totalCourseCount = courses.data.meta.page.total; - this.offset = Math.ceil(courses.data.meta.page.offset / this.limit); this.courses = courses.data.data; this.showingAllCourses = state; }); @@ -353,10 +326,8 @@ export default { }); if (this.withCourses) { - this.getNodeCourses(this.currentNode, 0, this.semester, this.semClass) + this.getNodeCourses(this.currentNode, this.semester, this.semClass) .then(courses => { - this.totalCourseCount = courses.data.meta.page.total; - this.offset = 0; this.courses = courses.data.data; }); } diff --git a/resources/vue/components/tree/TreeNodeCourseInfo.vue b/resources/vue/components/tree/TreeNodeCourseInfo.vue index 3f3777c933853066ba83eb23a58cc37e935f7544..db31d148c3f144ec4b221f91fd77667f5cf6f250 100644 --- a/resources/vue/components/tree/TreeNodeCourseInfo.vue +++ b/resources/vue/components/tree/TreeNodeCourseInfo.vue @@ -1,20 +1,33 @@ <template> <div class="studip-tree-child-description"> - <studip-loading-skeleton v-if="isLoading" /> + <template v-if="showingAllCourses"> + <div v-translate="{ count: courseCount }" :translate-n="courseCount" + translate-plural="<strong>%{count}</strong> Veranstaltungen auf dieser Ebene."> + <strong>Eine</strong> Veranstaltung auf dieser Ebene. + </div> + </template> <div v-else v-translate="{ count: courseCount }" :translate-n="courseCount" - translate-plural="<strong>%{count}</strong> Veranstaltungen"> - <strong>Eine</strong> Veranstaltung + translate-plural="<strong>%{count}</strong> Veranstaltungen auf dieser Ebene."> + <strong>Eine</strong> Veranstaltung auf dieser Ebene. + </div> + <template v-if="!showingAllCourses"> + <div v-translate="{ count: allCourseCount }" :translate-n="allCourseCount" + translate-plural="<strong>%{count}</strong> Veranstaltungen auf allen Unterebenen."> + <strong>Eine</strong> Veranstaltung auf allen Unterebenen. + </div> + </template> + <div v-else v-translate="{ count: allCourseCount }" :translate-n="allCourseCount" + translate-plural="<strong>%{count}</strong> Veranstaltungen auf allen Unterebenen."> + <strong>Eine</strong> Veranstaltung auf allen Unterebenen. </div> </div> </template> <script> import { TreeMixin } from '../../mixins/TreeMixin'; -import StudipLoadingSkeleton from '../StudipLoadingSkeleton.vue'; export default { name: 'TreeNodeCourseInfo', - components: { StudipLoadingSkeleton }, mixins: [ TreeMixin ], props: { node: { @@ -32,8 +45,8 @@ export default { }, data() { return { - isLoading: false, courseCount: 0, + allCourseCount: 0, showingAllCourses: false } }, @@ -41,22 +54,22 @@ export default { showAllCourses(state) { this.showingAllCourses = state; this.$emit('showAllCourses', state); - }, - loadNodeInfo(node) { - this.isLoading = true; - this.getNodeCourseInfo(node, this.semester, this.semClass) - .then(info => { - this.courseCount = info?.data.courses; - this.isLoading = false; - }); } }, mounted() { - this.loadNodeInfo(this.node); + this.getNodeCourseInfo(this.node, this.semester, this.semClass) + .then(info => { + this.courseCount = info?.data.courses; + this.allCourseCount = info?.data.allCourses; + }); }, watch: { node(newNode) { - this.loadNodeInfo(newNode); + this.getNodeCourseInfo(newNode, this.semester, this.semClass) + .then(info => { + this.courseCount = info?.data.courses; + this.allCourseCount = info?.data.allCourses; + }); } } } diff --git a/resources/vue/components/tree/TreeNodeTile.vue b/resources/vue/components/tree/TreeNodeTile.vue index dab2bdf9ff698e0c4333cdd1873338ac45a85769..cbb0679eaeffeedb844b823abf4a2a5c0293e955 100644 --- a/resources/vue/components/tree/TreeNodeTile.vue +++ b/resources/vue/components/tree/TreeNodeTile.vue @@ -5,11 +5,8 @@ {{ node.attributes.name }} </p> - <tree-node-course-info v-if="node.attributes.ancestors.length > 2" - :node="node" - :semester="semester" - :sem-class="semClass" - ></tree-node-course-info> + <tree-node-course-info :node="node" :semester="semester" + :sem-class="semClass"></tree-node-course-info> </a> </template> diff --git a/resources/vue/mixins/TreeMixin.js b/resources/vue/mixins/TreeMixin.js index 4263eaf938d269906d771e679752511642a073d2..9c4c859d7b092aba832c53186e52bb669b4c6a7b 100644 --- a/resources/vue/mixins/TreeMixin.js +++ b/resources/vue/mixins/TreeMixin.js @@ -3,10 +3,7 @@ import axios from 'axios'; export const TreeMixin = { data() { return { - showProgressIndicatorTimeout: 500, - totalCourseCount: 0, - offset: 0, - limit: 50 + showProgressIndicatorTimeout: 500 }; }, methods: { @@ -25,12 +22,9 @@ export const TreeMixin = { { params: parameters } ); }, - async getNodeCourses(node, offset, semesterId = 'all', semClass = 0, searchterm = '', recursive = false, ids = []) { + async getNodeCourses(node, semesterId = 'all', semClass = 0, searchterm = '', recursive = false, ids = []) { let parameters = {}; - parameters['page[offset]'] = offset * this.limit; - parameters['page[limit]'] = this.limit; - if (semesterId !== 'all' && semesterId !== '0') { parameters['filter[semester]'] = semesterId; } @@ -109,15 +103,6 @@ export const TreeMixin = { { headers: { 'Content-Type': 'multipart/form-data' }} ); STUDIP.Vue.emit('sort-tree-children', { parent: parentId, children: children }); - }, - updateOffset(newOffset) { - this.getNodeCourses(this.currentNode, newOffset, this.semester, this.semClass, '', this.showingAllCourses) - .then(courses => { - this.courseCount = courses.data.meta.page.total; - this.currentOffset = courses.data.meta.page.offset; - this.offset = newOffset; - this.courses = courses.data.data; - }); } } }