From 3cd4367aa9918a75867c6433c07d5c4da7335534 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Willms Date: Fri, 28 Mar 2025 14:22:10 +0100 Subject: wip --- app/controllers/admin/tree.php | 6 ++ lib/classes/JsonApi/Schemas/TreeNodeCourse.php | 21 +++++ resources/assets/stylesheets/scss/contentbar.scss | 2 +- resources/assets/stylesheets/scss/tree.scss | 36 ++++----- resources/vue/components/tree/StudipTree.vue | 68 +++++++++++++--- resources/vue/components/tree/StudipTreeList.vue | 80 +------------------ resources/vue/components/tree/StudipTreeNode.vue | 19 ++--- resources/vue/components/tree/StudipTreeTable.vue | 92 +--------------------- resources/vue/components/tree/TreeCourseTable.vue | 69 ++++++++++++++++ resources/vue/components/tree/TreeExportWidget.vue | 4 +- resources/vue/mixins/TreeMixin.js | 16 +--- resources/vue/store/TreeStore.js | 12 +-- 12 files changed, 198 insertions(+), 227 deletions(-) create mode 100644 resources/vue/components/tree/TreeCourseTable.vue diff --git a/app/controllers/admin/tree.php b/app/controllers/admin/tree.php index 5d22775..9bce2ea 100644 --- a/app/controllers/admin/tree.php +++ b/app/controllers/admin/tree.php @@ -28,6 +28,9 @@ class Admin_TreeController extends AuthenticatedController 'visible-children-only' => false, 'with-courses' => true, ]) + ->withVuexStore('TreeStore', 'treestore', [ + 'SET_SEMESTER' => $this->semester, + ]) ); } @@ -59,6 +62,9 @@ class Admin_TreeController extends AuthenticatedController 'with-course-assign' => true, 'with-courses' => true, ]) + ->withVuexStore('TreeStore', 'treestore', [ + 'SET_SEMESTER' => $this->semester, + ]) ); } diff --git a/lib/classes/JsonApi/Schemas/TreeNodeCourse.php b/lib/classes/JsonApi/Schemas/TreeNodeCourse.php index 85f4226..331fc17 100644 --- a/lib/classes/JsonApi/Schemas/TreeNodeCourse.php +++ b/lib/classes/JsonApi/Schemas/TreeNodeCourse.php @@ -34,8 +34,29 @@ final class TreeNodeCourse extends SchemaProvider ); } + /** + * @param Model $resource + */ public function getRelationships($resource, ContextInterface $context): iterable { return []; } + + /** + * @param Model $resource + */ + public function hasResourceMeta($resource): bool + { + $schema = $this->schemaContainer->getSchema($resource->getCourse()); + return $schema->hasResourceMeta($resource->getCourse()); + } + + /** + * @param Model $resource + */ + public function getResourceMeta($resource) + { + $schema = $this->schemaContainer->getSchema($resource->getCourse()); + return $schema->getResourceMeta($resource->getCourse()); + } } diff --git a/resources/assets/stylesheets/scss/contentbar.scss b/resources/assets/stylesheets/scss/contentbar.scss index b582ec5..72a8f78 100644 --- a/resources/assets/stylesheets/scss/contentbar.scss +++ b/resources/assets/stylesheets/scss/contentbar.scss @@ -15,7 +15,7 @@ .contentbar-wrapper-left { display: flex; - max-width: calc(100% - 130px); + flex: 1 0 calc(100% - 130px); .contentbar-breadcrumb { font-size: 1.25em; diff --git a/resources/assets/stylesheets/scss/tree.scss b/resources/assets/stylesheets/scss/tree.scss index 1d700f9..1c46031 100644 --- a/resources/assets/stylesheets/scss/tree.scss +++ b/resources/assets/stylesheets/scss/tree.scss @@ -14,7 +14,7 @@ $tree-outline: 1px solid var(--light-gray-color-40); } .contentbar { - display: relative; + display: flex; .contentbar-wrapper-right { display: inherit; @@ -308,23 +308,6 @@ $tree-outline: 1px solid var(--light-gray-color-40); } } } - - table { - tr { - td { - line-height: 24px; - padding: 10px; - vertical-align: top; - - a { - img { - margin-right: 5px; - vertical-align: bottom; - } - } - } - } - } } /* Display as table */ @@ -371,6 +354,23 @@ $tree-outline: 1px solid var(--light-gray-color-40); } } + .studip-tree-courses-table { + tr { + td { + line-height: 24px; + padding: 10px; + vertical-align: top; + + a { + img { + margin-right: 5px; + vertical-align: bottom; + } + } + } + } + } + .studip-tree-course-path { font-size: 0.9em; list-style: none; diff --git a/resources/vue/components/tree/StudipTree.vue b/resources/vue/components/tree/StudipTree.vue index 7e0d599..c0a1d82 100644 --- a/resources/vue/components/tree/StudipTree.vue +++ b/resources/vue/components/tree/StudipTree.vue @@ -19,19 +19,44 @@ :with-export="withExport" :show-structure-as-navigation="showStructureAsNavigation" :assignable="assignable" - :with-course-assign="withCourseAssign" + :page="currentPage" @change-current-node="changeCurrentNode" > + + + +
+ + + + + + + + + - + + + name="sidebar-views" + > @@ -48,17 +73,25 @@ import StudipTreeList from './StudipTreeList.vue'; import StudipTreeTable from './StudipTreeTable.vue'; import StudipTreeNode from './StudipTreeNode.vue'; import TreeSearchResult from './TreeSearchResult.vue'; +import TreeCourseTable from "./TreeCourseTable.vue"; +import StudipPagination from "../StudipPagination.vue"; +import TreeExportWidget from "./TreeExportWidget.vue"; +import AssignLinkWidget from "./AssignLinkWidget.vue"; export default { name: 'StudipTree', components: { - TreeSearchResult, + AssignLinkWidget, SearchWidget, - StudipTreeViewWidget, + StudipPagination, StudipProgressIndicator, StudipTreeList, + StudipTreeNode, StudipTreeTable, - StudipTreeNode + StudipTreeViewWidget, + TreeCourseTable, + TreeExportWidget, + TreeSearchResult }, mixins: [ TreeMixin ], props: { @@ -153,8 +186,11 @@ export default { }, data() { return { + courses: [], + nodeId: this.startId, startNode: null, + currentPage: 0, currentNode: this.startNode, loaded: false, isLoading: false, @@ -165,6 +201,12 @@ export default { } }, computed: { + exportUrl() { + return STUDIP.URLHelper.getURL('dispatch.php/tree/export_csv'); + }, + showExport() { + return this.withExport && document.getElementById('export-widget'); + }, viewComponent() { if (this.startNode && this.viewType === 'list') { return StudipTreeList; @@ -193,9 +235,6 @@ export default { document.getElementById('tree-breadcrumb-' + node.attributes.id)?.focus(); }); }, - exportUrl() { - return STUDIP.URLHelper.getURL('dispatch.php/tree/export_csv'); - }, injectSearchterm(targetId, searchterm) { const form = document.getElementById(targetId).querySelector('form'); let input = form.querySelector('input[type="hidden"][name="search"]'); @@ -262,6 +301,17 @@ export default { document.getElementById('semclass-selector-searchterm')?.remove(); this.isSearching = false; }); + }, + watch: { + async currentNode(node) { + if (this.withCourses) { + this.courses = await this.fetchNodeCourses(node.id); + } + }, + currentPage(current) { + this.updateOffset(current); + } } + } diff --git a/resources/vue/components/tree/StudipTreeList.vue b/resources/vue/components/tree/StudipTreeList.vue index d96c235..6db7232 100644 --- a/resources/vue/components/tree/StudipTreeList.vue +++ b/resources/vue/components/tree/StudipTreeList.vue @@ -73,86 +73,20 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{ $gettext('Veranstaltungen') }}
- -
{{ $gettext('Name') }}{{ $gettext('Information') }}
- - - - {{ course.attributes.title }} - -
-
- -
- -
- - - - - - diff --git a/resources/vue/components/tree/TreeExportWidget.vue b/resources/vue/components/tree/TreeExportWidget.vue index 61500f5..bb47c67 100644 --- a/resources/vue/components/tree/TreeExportWidget.vue +++ b/resources/vue/components/tree/TreeExportWidget.vue @@ -3,7 +3,9 @@ diff --git a/resources/vue/mixins/TreeMixin.js b/resources/vue/mixins/TreeMixin.js index 43ef469..72bc235 100644 --- a/resources/vue/mixins/TreeMixin.js +++ b/resources/vue/mixins/TreeMixin.js @@ -11,8 +11,7 @@ export const TreeMixin = { data() { return { currentNode: null, - showProgressIndicatorTimeout: 500, - page: 0 + showProgressIndicatorTimeout: 500 }; }, computed: { @@ -28,7 +27,7 @@ export const TreeMixin = { ]), totalCourseCount() { - return this.getNodeCoursesTotal(this.currentNode.id); + return this.getNodeCoursesTotal(this.currentNode?.id); } }, methods: { @@ -84,15 +83,9 @@ export const TreeMixin = { nodeUrl(node_id, semester = null ) { return STUDIP.URLHelper.getURL('', { node_id, semester }) }, - courseUrl(courseId) { - return STUDIP.URLHelper.getURL('dispatch.php/course/details/index/' + courseId) - }, profileUrl(username) { return STUDIP.URLHelper.getURL('dispatch.php/profile', { username }) }, - exportUrl() { - return STUDIP.URLHelper.getURL('dispatch.php/tree/export_csv'); - }, editNode(editUrl, id) { STUDIP.Dialog.fromURL( editUrl + '/' + id, @@ -129,10 +122,5 @@ export const TreeMixin = { page }); } - }, - watch: { - page(current) { - this.updateOffset(current); - } } } diff --git a/resources/vue/store/TreeStore.js b/resources/vue/store/TreeStore.js index 9d9cf00..4de27e9 100644 --- a/resources/vue/store/TreeStore.js +++ b/resources/vue/store/TreeStore.js @@ -40,11 +40,11 @@ class DataRequest return DataRequest.#promises[index]; } - const promise = DataRequest.#apiRequest(request.path, request.parameters); - DataRequest.#promises[index] = promise; - return promise.then(handler).finally(() => { - delete DataRequest.#promises[index]; - }); + return DataRequest.#promises[index] = DataRequest.#apiRequest(request.path, request.parameters) + .then(handler) + .finally(() => { + delete DataRequest.#promises[index]; + }); } } @@ -61,7 +61,7 @@ export default { isLoading: false, semesterId: 'all', semClass: 0, - viewType: 'tree' + viewType: 'table' }), getters: { getNode: (state) => (id) => { -- cgit v1.0