mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-05-10 15:09:07 +00:00
feat: expandable accordion in grades module
This commit is contained in:
402
package-lock.json
generated
402
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
74
src/app/_helpers/collections/tree-group.spec.ts
Normal file
74
src/app/_helpers/collections/tree-group.spec.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Tree, treeGroupBy} from './tree-group';
|
||||||
|
|
||||||
|
interface TestItem {
|
||||||
|
id: number;
|
||||||
|
path?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('tree-group', function () {
|
||||||
|
it('should create a tree', function () {
|
||||||
|
const items: Array<TestItem> = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
path: ['a', 'b', 'c'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
path: ['a', 'b', 'd'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const tree = treeGroupBy(items, item => item.path ?? []);
|
||||||
|
|
||||||
|
const expectedTree: Tree<TestItem> = {
|
||||||
|
a: {
|
||||||
|
b: {
|
||||||
|
c: {_: [items[0]]},
|
||||||
|
d: {_: [items[1]]},
|
||||||
|
} as Tree<TestItem>,
|
||||||
|
} as Tree<TestItem>,
|
||||||
|
} as Tree<TestItem>;
|
||||||
|
|
||||||
|
expect(tree).toEqual(expectedTree);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should also sort empty paths', () => {
|
||||||
|
const items: Array<TestItem> = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
path: ['a', 'b', 'c'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const tree = treeGroupBy(items, item => item.path ?? []);
|
||||||
|
|
||||||
|
const expectedTree: Tree<TestItem> = {
|
||||||
|
a: {
|
||||||
|
b: {
|
||||||
|
c: {_: [items[0]]},
|
||||||
|
} as Tree<TestItem>,
|
||||||
|
} as Tree<TestItem>,
|
||||||
|
_: [items[1]],
|
||||||
|
} as Tree<TestItem>;
|
||||||
|
|
||||||
|
expect(tree).toEqual(expectedTree);
|
||||||
|
});
|
||||||
|
});
|
||||||
49
src/app/_helpers/collections/tree-group.ts
Normal file
49
src/app/_helpers/collections/tree-group.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type Tree<T> = {
|
||||||
|
[key: string]: Tree<T>;
|
||||||
|
} & {
|
||||||
|
_?: T[] | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function treeGroupBy<T>(
|
||||||
|
items: T[],
|
||||||
|
transform: (item: T) => string[],
|
||||||
|
): Tree<T> {
|
||||||
|
const tree: Tree<T> = {};
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
let currentTree = tree;
|
||||||
|
const keys = transform(item);
|
||||||
|
if (keys.length === 0) {
|
||||||
|
currentTree._ = currentTree._ || [];
|
||||||
|
currentTree._.push(item);
|
||||||
|
}
|
||||||
|
for (const [i, key] of keys.entries()) {
|
||||||
|
currentTree = currentTree[key] = (currentTree[key] ?? {}) as Tree<T>;
|
||||||
|
if (i === keys.length - 1) {
|
||||||
|
currentTree._ = currentTree._ ?? [];
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
currentTree._.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import {AssessmentsDetailComponent} from './detail/assessments-detail.component'
|
|||||||
import {AssessmentsProvider} from './assessments.provider';
|
import {AssessmentsProvider} from './assessments.provider';
|
||||||
import {AssessmentsSimpleDataListComponent} from './list/assessments-simple-data-list.component';
|
import {AssessmentsSimpleDataListComponent} from './list/assessments-simple-data-list.component';
|
||||||
import {ProtectedRoutes} from '../auth/protected.routes';
|
import {ProtectedRoutes} from '../auth/protected.routes';
|
||||||
|
import {AssessmentsTreeListComponent} from './list/assessments-tree-list.component';
|
||||||
|
|
||||||
const routes: ProtectedRoutes = [
|
const routes: ProtectedRoutes = [
|
||||||
{
|
{
|
||||||
@@ -56,6 +57,7 @@ const routes: ProtectedRoutes = [
|
|||||||
AssessmentBaseInfoComponent,
|
AssessmentBaseInfoComponent,
|
||||||
AssessmentDetailComponent,
|
AssessmentDetailComponent,
|
||||||
AssessmentsListItemComponent,
|
AssessmentsListItemComponent,
|
||||||
|
AssessmentsTreeListComponent,
|
||||||
CourseOfStudyAssessmentComponent,
|
CourseOfStudyAssessmentComponent,
|
||||||
AssessmentsPageComponent,
|
AssessmentsPageComponent,
|
||||||
AssessmentsDataListComponent,
|
AssessmentsDataListComponent,
|
||||||
|
|||||||
@@ -13,29 +13,60 @@
|
|||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, ViewChild} from '@angular/core';
|
import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
|
||||||
import {ActivatedRoute} from '@angular/router';
|
import {ActivatedRoute} from '@angular/router';
|
||||||
import {AssessmentsProvider} from '../assessments.provider';
|
import {AssessmentsProvider} from '../assessments.provider';
|
||||||
import {
|
import {
|
||||||
DataDetailComponent,
|
DataDetailComponent,
|
||||||
ExternalDataLoadEvent,
|
ExternalDataLoadEvent,
|
||||||
} from '../../data/detail/data-detail.component';
|
} from '../../data/detail/data-detail.component';
|
||||||
import {ViewWillEnter} from '@ionic/angular';
|
import {NavController, ViewWillEnter} from '@ionic/angular';
|
||||||
|
import {Subscription} from 'rxjs';
|
||||||
|
import {DataRoutingService} from '../../data/data-routing.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'assessments-detail',
|
selector: 'assessments-detail',
|
||||||
templateUrl: 'assessments-detail.html',
|
templateUrl: 'assessments-detail.html',
|
||||||
styleUrls: ['assessments-detail.scss'],
|
styleUrls: ['assessments-detail.scss'],
|
||||||
})
|
})
|
||||||
export class AssessmentsDetailComponent implements ViewWillEnter {
|
export class AssessmentsDetailComponent
|
||||||
|
implements ViewWillEnter, OnInit, OnDestroy
|
||||||
|
{
|
||||||
constructor(
|
constructor(
|
||||||
readonly route: ActivatedRoute,
|
readonly route: ActivatedRoute,
|
||||||
readonly assessmentsProvider: AssessmentsProvider,
|
readonly assessmentsProvider: AssessmentsProvider,
|
||||||
|
readonly dataRoutingService: DataRoutingService,
|
||||||
|
readonly navController: NavController,
|
||||||
|
readonly activatedRoute: ActivatedRoute,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
|
@Input() dataPathAutoRouting = true;
|
||||||
|
|
||||||
@ViewChild(DataDetailComponent)
|
@ViewChild(DataDetailComponent)
|
||||||
detailComponent: DataDetailComponent;
|
detailComponent: DataDetailComponent;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (!this.dataPathAutoRouting) return;
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.dataRoutingService.pathSelectListener().subscribe(item => {
|
||||||
|
void this.navController.navigateBack(
|
||||||
|
['assessments', 'detail', item.uid],
|
||||||
|
{
|
||||||
|
queryParams: {
|
||||||
|
token: this.activatedRoute.snapshot.queryParamMap.get('token'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
for (const sub of this.subscriptions) sub.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
getItem(event: ExternalDataLoadEvent) {
|
getItem(event: ExternalDataLoadEvent) {
|
||||||
this.assessmentsProvider
|
this.assessmentsProvider
|
||||||
.getAssessments(
|
.getAssessments(
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<stapps-data-detail
|
<stapps-data-detail
|
||||||
|
[autoRouteDataPath]="false"
|
||||||
[externalData]="true"
|
[externalData]="true"
|
||||||
(loadItem)="getItem($event)"
|
(loadItem)="getItem($event)"
|
||||||
[defaultHeader]="false"
|
[defaultHeader]="false"
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component, Input} from '@angular/core';
|
||||||
|
import {SCThings} from '@openstapps/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'assessments-tree-list',
|
||||||
|
templateUrl: 'assessments-tree-list.html',
|
||||||
|
styleUrls: ['assessments-tree-list.scss'],
|
||||||
|
})
|
||||||
|
export class AssessmentsTreeListComponent {
|
||||||
|
@Input() items?: Promise<SCThings[] | undefined>;
|
||||||
|
|
||||||
|
@Input() singleType = false;
|
||||||
|
|
||||||
|
@Input() groupingKey: string;
|
||||||
|
}
|
||||||
27
src/app/modules/assessments/list/assessments-tree-list.html
Normal file
27
src/app/modules/assessments/list/assessments-tree-list.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2022 StApps
|
||||||
|
~ This program is free software: you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU General Public License as published by the Free
|
||||||
|
~ Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
~ more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License along with
|
||||||
|
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<tree-list
|
||||||
|
[items]="items"
|
||||||
|
[singleType]="singleType"
|
||||||
|
[groupingKey]="groupingKey"
|
||||||
|
>
|
||||||
|
<ng-template let-item>
|
||||||
|
<assessments-list-item
|
||||||
|
[item]="item"
|
||||||
|
[hideThumbnail]="singleType"
|
||||||
|
></assessments-list-item>
|
||||||
|
</ng-template>
|
||||||
|
</tree-list>
|
||||||
15
src/app/modules/assessments/list/assessments-tree-list.scss
Normal file
15
src/app/modules/assessments/list/assessments-tree-list.scss
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
padding-inline: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,29 @@
|
|||||||
<ion-note *ngIf="item.courseOfStudy as courseOfStudy">
|
<!--
|
||||||
|
~ Copyright (C) 2022 StApps
|
||||||
|
~ This program is free software: you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU General Public License as published by the Free
|
||||||
|
~ Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
~ more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License along with
|
||||||
|
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ion-card>
|
||||||
|
<ion-card-content>
|
||||||
|
<ion-note *ngIf="item.courseOfStudy as courseOfStudy">
|
||||||
{{ $any('courseOfStudy' | propertyNameTranslate: item) | titlecase }}:
|
{{ $any('courseOfStudy' | propertyNameTranslate: item) | titlecase }}:
|
||||||
{{ 'name' | thingTranslate: $any(courseOfStudy) }}
|
{{ 'name' | thingTranslate: $any(courseOfStudy) }}
|
||||||
({{ 'academicDegree' | thingTranslate: $any(courseOfStudy) }})
|
({{ 'academicDegree' | thingTranslate: $any(courseOfStudy) }})
|
||||||
</ion-note>
|
</ion-note>
|
||||||
|
</ion-card-content>
|
||||||
|
</ion-card>
|
||||||
<ion-list class="container">
|
<ion-list class="container">
|
||||||
<ion-item lines="none">
|
<ion-item lines="none">
|
||||||
<assessment-base-info [item]="item"></assessment-base-info>
|
<assessment-base-info [item]="item"></assessment-base-info>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<h2 *ngIf="item.superAssessments">
|
|
||||||
{{ $any('superAssessments' | propertyNameTranslate: item) | titlecase }}
|
|
||||||
</h2>
|
|
||||||
<assessments-simple-data-list
|
|
||||||
*ngIf="item.superAssessments"
|
|
||||||
[items]="$any(item.superAssessments)"
|
|
||||||
[singleType]="true"
|
|
||||||
></assessments-simple-data-list>
|
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
<h2 class="name">
|
<!--
|
||||||
|
~ Copyright (C) 2022 StApps
|
||||||
|
~ This program is free software: you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU General Public License as published by the Free
|
||||||
|
~ Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
~ more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License along with
|
||||||
|
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="name">
|
||||||
{{ 'name' | thingTranslate: item }}
|
{{ 'name' | thingTranslate: item }}
|
||||||
{{ item.date ? (item.date | amDateFormat) : '' }}
|
{{ item.date ? (item.date | amDateFormat) : '' }}
|
||||||
</h2>
|
</h2>
|
||||||
<assessment-base-info [item]="item"></assessment-base-info>
|
<assessment-base-info [item]="item"></assessment-base-info>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.column {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
height: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-indicator {
|
||||||
|
width: 16px;
|
||||||
|
margin-right: 4px;
|
||||||
|
padding-left: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.super-assessments-list {
|
||||||
|
// prevent the list from hijacking hover overlays
|
||||||
|
z-index: -1;
|
||||||
|
|
||||||
|
:last-child {
|
||||||
|
.tree-indicator-after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,21 +25,23 @@ import {sum, sumBy} from '../../../../_helpers/collections/sum';
|
|||||||
export class CourseOfStudyAssessmentComponent {
|
export class CourseOfStudyAssessmentComponent {
|
||||||
@Input() courseOfStudy: SCCourseOfStudyWithoutReferences | null;
|
@Input() courseOfStudy: SCCourseOfStudyWithoutReferences | null;
|
||||||
|
|
||||||
_assessments: SCAssessment[];
|
_assessments: Promise<SCAssessment[]>;
|
||||||
|
|
||||||
grade = 0;
|
grade = 0;
|
||||||
|
|
||||||
ects = 0;
|
ects = 0;
|
||||||
|
|
||||||
@Input() set assessments(value: SCAssessment[]) {
|
@Input() set assessments(value: SCAssessment[]) {
|
||||||
this._assessments = value;
|
const assessments = value;
|
||||||
|
|
||||||
const grades = this._assessments
|
const grades = assessments
|
||||||
// TODO: find out if this is correct
|
// TODO: find out if this is correct
|
||||||
.filter(assessment => assessment.status === 'bestanden')
|
.filter(assessment => assessment.status === 'bestanden')
|
||||||
.map(assessment => Number(assessment.grade))
|
.map(assessment => Number(assessment.grade))
|
||||||
.filter(grade => !Number.isNaN(grade));
|
.filter(grade => !Number.isNaN(grade));
|
||||||
this.grade = grades.length > 0 ? sum(grades) / grades.length : 0;
|
this.grade = grades.length > 0 ? sum(grades) / grades.length : 0;
|
||||||
this.ects = sumBy(this._assessments, it => it.ects);
|
this.ects = sumBy(assessments, it => it.ects);
|
||||||
|
|
||||||
|
this._assessments = Promise.resolve(assessments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,25 +13,25 @@
|
|||||||
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<assessments-data-list
|
<section>
|
||||||
[singleType]="true"
|
|
||||||
[items]="_assessments"
|
|
||||||
[loading]="false"
|
|
||||||
>
|
|
||||||
<div header>
|
|
||||||
<section>
|
|
||||||
<h3>{{ 'assessments.courseOfStudyAssessments.PROGRESS' | translate }}</h3>
|
<h3>{{ 'assessments.courseOfStudyAssessments.PROGRESS' | translate }}</h3>
|
||||||
<p>
|
<p>
|
||||||
{{ $any('grade' | propertyNameTranslate: 'assessment') | titlecase }}:
|
{{ $any('grade' | propertyNameTranslate: 'assessment') | titlecase }}:
|
||||||
{{
|
{{
|
||||||
grade
|
grade | numberLocalized: 'minimumFractionDigits:1,maximumFractionDigits:1'
|
||||||
| numberLocalized: 'minimumFractionDigits:1,maximumFractionDigits:1'
|
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
<p>{{ 'ects' | propertyNameTranslate: 'assessment' }}: {{ ects }}</p>
|
<p>{{ 'ects' | propertyNameTranslate: 'assessment' }}: {{ ects }}</p>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
<h3>
|
<h3>
|
||||||
{{ 'assessments.courseOfStudyAssessments.ASSESSMENTS' | translate }}
|
{{ 'assessments.courseOfStudyAssessments.ASSESSMENTS' | translate }}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
|
||||||
</assessments-data-list>
|
<assessments-tree-list
|
||||||
|
[items]="_assessments"
|
||||||
|
[singleType]="true"
|
||||||
|
[groupingKey]="'superAssessments'"
|
||||||
|
>
|
||||||
|
</assessments-tree-list>
|
||||||
|
</section>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {SCThings} from '@openstapps/core';
|
import {SCThings, SCThingWithoutReferences} from '@openstapps/core';
|
||||||
import {Subject} from 'rxjs';
|
import {Subject} from 'rxjs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,6 +28,8 @@ export class DataRoutingService {
|
|||||||
*/
|
*/
|
||||||
private childSelectedEvent = new Subject<SCThings>();
|
private childSelectedEvent = new Subject<SCThings>();
|
||||||
|
|
||||||
|
private pathSelectedEvent = new Subject<SCThingWithoutReferences>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the thing that was selected
|
* Provides the thing that was selected
|
||||||
*
|
*
|
||||||
@@ -37,10 +39,18 @@ export class DataRoutingService {
|
|||||||
this.childSelectedEvent.next(thing);
|
this.childSelectedEvent.next(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitPathEvent(thing: SCThingWithoutReferences) {
|
||||||
|
this.pathSelectedEvent.next(thing);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a listener for the event
|
* Provides a listener for the event
|
||||||
*/
|
*/
|
||||||
itemSelectListener() {
|
itemSelectListener() {
|
||||||
return this.childSelectedEvent.asObservable();
|
return this.childSelectedEvent.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathSelectListener() {
|
||||||
|
return this.pathSelectedEvent.asObservable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ import {RoutingStackService} from '../../util/routing-stack.service';
|
|||||||
import {DataPathComponent} from './detail/data-path.component';
|
import {DataPathComponent} from './detail/data-path.component';
|
||||||
import {EventRoutePathComponent} from './types/event/event-route-path.component';
|
import {EventRoutePathComponent} from './types/event/event-route-path.component';
|
||||||
import {UtilModule} from '../../util/util.module';
|
import {UtilModule} from '../../util/util.module';
|
||||||
|
import {TreeListComponent} from './list/tree-list.component';
|
||||||
|
import {TreeListFragmentComponent} from './list/tree-list-fragment.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module for handling data
|
* Module for handling data
|
||||||
@@ -140,6 +142,8 @@ import {UtilModule} from '../../util/util.module';
|
|||||||
SkeletonListItemComponent,
|
SkeletonListItemComponent,
|
||||||
SkeletonSegmentComponent,
|
SkeletonSegmentComponent,
|
||||||
SkeletonSimpleCardComponent,
|
SkeletonSimpleCardComponent,
|
||||||
|
TreeListComponent,
|
||||||
|
TreeListFragmentComponent,
|
||||||
VideoDetailContentComponent,
|
VideoDetailContentComponent,
|
||||||
VideoListItemComponent,
|
VideoListItemComponent,
|
||||||
SimpleDataListComponent,
|
SimpleDataListComponent,
|
||||||
@@ -192,6 +196,7 @@ import {UtilModule} from '../../util/util.module';
|
|||||||
ArticleDetailContentComponent,
|
ArticleDetailContentComponent,
|
||||||
OriginDetailComponent,
|
OriginDetailComponent,
|
||||||
FavoriteButtonComponent,
|
FavoriteButtonComponent,
|
||||||
|
TreeListComponent,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class DataModule {}
|
export class DataModule {}
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ export class DataDetailComponent implements ViewWillEnter {
|
|||||||
|
|
||||||
@Input() isModal = false;
|
@Input() isModal = false;
|
||||||
|
|
||||||
|
@Input() autoRouteDataPath = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The language of the item
|
* The language of the item
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<div [ngSwitch]="true">
|
<div [ngSwitch]="true">
|
||||||
<ng-container *ngSwitchCase="!item && (isDisconnected | async)">
|
<ng-container *ngSwitchCase="!item && (isDisconnected | async)">
|
||||||
<div class="centeredMessageContainer">
|
<div class="centeredMessageContainer">
|
||||||
<ion-icon name="no-connection"> </ion-icon>
|
<ion-icon name="no-connection"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
{{ 'data.detail.COULD_NOT_CONNECT' | translate }}
|
{{ 'data.detail.COULD_NOT_CONNECT' | translate }}
|
||||||
</ion-label>
|
</ion-label>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngSwitchCase="item === null">
|
<ng-container *ngSwitchCase="item === null">
|
||||||
<div class="centeredMessageContainer">
|
<div class="centeredMessageContainer">
|
||||||
<ion-icon name="broken-link"> </ion-icon>
|
<ion-icon name="broken-link"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
{{ 'data.detail.NOT_FOUND' | translate }}
|
{{ 'data.detail.NOT_FOUND' | translate }}
|
||||||
</ion-label>
|
</ion-label>
|
||||||
@@ -65,7 +65,10 @@
|
|||||||
<stapps-skeleton-simple-card></stapps-skeleton-simple-card>
|
<stapps-skeleton-simple-card></stapps-skeleton-simple-card>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngSwitchDefault>
|
<ng-container *ngSwitchDefault>
|
||||||
<stapps-data-path [item]="item"></stapps-data-path>
|
<stapps-data-path
|
||||||
|
[item]="item"
|
||||||
|
[autoRouting]="autoRouteDataPath"
|
||||||
|
></stapps-data-path>
|
||||||
<stapps-data-detail-content
|
<stapps-data-detail-content
|
||||||
[item]="item"
|
[item]="item"
|
||||||
[contentTemplateRef]="contentTemplateRef"
|
[contentTemplateRef]="contentTemplateRef"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Component, Input, OnInit} from '@angular/core';
|
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {RoutingStackService} from '../../../util/routing-stack.service';
|
import {RoutingStackService} from '../../../util/routing-stack.service';
|
||||||
import {
|
import {
|
||||||
SCCatalog,
|
SCCatalog,
|
||||||
@@ -21,24 +21,24 @@ import {
|
|||||||
SCThingWithoutReferences,
|
SCThingWithoutReferences,
|
||||||
} from '@openstapps/core';
|
} from '@openstapps/core';
|
||||||
import {DataProvider, DataScope} from '../data.provider';
|
import {DataProvider, DataScope} from '../data.provider';
|
||||||
import {fromEvent, Observable} from 'rxjs';
|
import {fromEvent, Observable, Subscription} from 'rxjs';
|
||||||
import {map} from 'rxjs/operators';
|
import {map, startWith} from 'rxjs/operators';
|
||||||
|
import {DataRoutingService} from '../data-routing.service';
|
||||||
|
import {NavController} from '@ionic/angular';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'stapps-data-path',
|
selector: 'stapps-data-path',
|
||||||
templateUrl: './data-path.html',
|
templateUrl: './data-path.html',
|
||||||
styleUrls: ['./data-path.scss'],
|
styleUrls: ['./data-path.scss'],
|
||||||
})
|
})
|
||||||
export class DataPathComponent implements OnInit {
|
export class DataPathComponent implements OnInit, OnDestroy {
|
||||||
path: Promise<SCThingWithoutReferences[]>;
|
path: Promise<SCThingWithoutReferences[]>;
|
||||||
|
|
||||||
$width: Observable<number>;
|
$width: Observable<number>;
|
||||||
|
|
||||||
ngOnInit() {
|
subscriptions: Subscription[] = [];
|
||||||
this.$width = fromEvent(window, 'resize').pipe(
|
|
||||||
map(() => window.innerWidth),
|
@Input() autoRouting = true;
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input() set item(item: SCThings) {
|
@Input() set item(item: SCThings) {
|
||||||
// eslint-disable-next-line unicorn/prefer-ternary
|
// eslint-disable-next-line unicorn/prefer-ternary
|
||||||
@@ -47,6 +47,11 @@ export class DataPathComponent implements OnInit {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
resolve([...item.superCatalogs!, item]),
|
resolve([...item.superCatalogs!, item]),
|
||||||
);
|
);
|
||||||
|
} else if (item.type === SCThingType.Assessment && item.superAssessments) {
|
||||||
|
this.path = new Promise(resolve =>
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
resolve([...item.superAssessments!, item]),
|
||||||
|
);
|
||||||
} else if (
|
} else if (
|
||||||
item.type === SCThingType.AcademicEvent &&
|
item.type === SCThingType.AcademicEvent &&
|
||||||
item.catalogs &&
|
item.catalogs &&
|
||||||
@@ -76,7 +81,27 @@ export class DataPathComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
readonly dataRoutingService: DataRoutingService,
|
||||||
|
readonly navController: NavController,
|
||||||
readonly routeStack: RoutingStackService,
|
readonly routeStack: RoutingStackService,
|
||||||
readonly dataProvider: DataProvider,
|
readonly dataProvider: DataProvider,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.$width = fromEvent(window, 'resize').pipe(
|
||||||
|
map(() => window.innerWidth),
|
||||||
|
startWith(window.innerWidth),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!this.autoRouting) return;
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.dataRoutingService.pathSelectListener().subscribe(item => {
|
||||||
|
void this.navController.navigateBack(['data-detail', item.uid]);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
for (const sub of this.subscriptions) sub.unsubscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,7 @@
|
|||||||
>
|
>
|
||||||
<ion-breadcrumb *ngFor="let fragment of stack">
|
<ion-breadcrumb *ngFor="let fragment of stack">
|
||||||
<ion-label
|
<ion-label
|
||||||
[routerLink]="['/data-detail', fragment.uid]"
|
(click)="dataRoutingService.emitPathEvent(fragment)"
|
||||||
[routerDirection]="'back'"
|
|
||||||
[style.max-width]="
|
[style.max-width]="
|
||||||
stack.length === 1
|
stack.length === 1
|
||||||
? '100%'
|
? '100%'
|
||||||
@@ -42,10 +41,11 @@
|
|||||||
<ng-template>
|
<ng-template>
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-item
|
<ion-item
|
||||||
|
button
|
||||||
*ngFor="let fragment of stack"
|
*ngFor="let fragment of stack"
|
||||||
(click)="popover.dismiss()"
|
(click)="
|
||||||
[routerLink]="['/data-detail', fragment.uid]"
|
dataRoutingService.emitPathEvent(fragment); popover.dismiss()
|
||||||
[routerDirection]="'back'"
|
"
|
||||||
>{{ 'name' | thingTranslate: $any(fragment) }}</ion-item
|
>{{ 'name' | thingTranslate: $any(fragment) }}</ion-item
|
||||||
>
|
>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|||||||
44
src/app/modules/data/list/tree-list-fragment.component.ts
Normal file
44
src/app/modules/data/list/tree-list-fragment.component.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {Component, Input, TemplateRef} from '@angular/core';
|
||||||
|
import {SCThings, SCThingWithoutReferences, SCUuid} from '@openstapps/core';
|
||||||
|
import {Tree} from '../../../_helpers/collections/tree-group';
|
||||||
|
import {DataListContext} from './data-list.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tree-list-fragment',
|
||||||
|
templateUrl: 'tree-list-fragment.html',
|
||||||
|
styleUrls: ['tree-list-fragment.scss'],
|
||||||
|
})
|
||||||
|
export class TreeListFragmentComponent {
|
||||||
|
entries?: [string, Tree<SCThings>][];
|
||||||
|
|
||||||
|
@Input() set items(items: Tree<SCThings> | undefined) {
|
||||||
|
if (!items) {
|
||||||
|
delete this.entries;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const temporary = items._;
|
||||||
|
delete items._;
|
||||||
|
this.entries = Object.entries(items) as [string, Tree<SCThings>][];
|
||||||
|
items._ = temporary;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input() groupMap: Record<SCUuid, SCThingWithoutReferences>;
|
||||||
|
|
||||||
|
@Input() singleType = false;
|
||||||
|
|
||||||
|
@Input() listItemTemplateRef: TemplateRef<DataListContext<SCThings>>;
|
||||||
|
}
|
||||||
45
src/app/modules/data/list/tree-list-fragment.html
Normal file
45
src/app/modules/data/list/tree-list-fragment.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2022 StApps
|
||||||
|
~ This program is free software: you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU General Public License as published by the Free
|
||||||
|
~ Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
~ more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License along with
|
||||||
|
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ion-accordion-group *ngIf="entries as entries" [value]="entries[0]?.[0]">
|
||||||
|
<ion-accordion *ngFor="let entry of entries" [value]="entry[0]">
|
||||||
|
<ion-item *ngIf="groupMap[entry[0]] as header" slot="header">
|
||||||
|
<ion-label>{{ header.name }}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-list slot="content">
|
||||||
|
<ng-container *ngFor="let item of entry[1]._ || []">
|
||||||
|
<ng-container
|
||||||
|
*ngTemplateOutlet="
|
||||||
|
listItemTemplateRef || defaultListItem;
|
||||||
|
context: {$implicit: item}
|
||||||
|
"
|
||||||
|
></ng-container>
|
||||||
|
</ng-container>
|
||||||
|
<tree-list-fragment
|
||||||
|
[groupMap]="groupMap"
|
||||||
|
[items]="entry[1]"
|
||||||
|
[singleType]="singleType"
|
||||||
|
[listItemTemplateRef]="listItemTemplateRef"
|
||||||
|
></tree-list-fragment>
|
||||||
|
</ion-list>
|
||||||
|
</ion-accordion>
|
||||||
|
</ion-accordion-group>
|
||||||
|
|
||||||
|
<ng-template let-item #defaultListItem>
|
||||||
|
<stapps-data-list-item
|
||||||
|
[item]="item"
|
||||||
|
[hideThumbnail]="singleType"
|
||||||
|
></stapps-data-list-item>
|
||||||
|
</ng-template>
|
||||||
18
src/app/modules/data/list/tree-list-fragment.scss
Normal file
18
src/app/modules/data/list/tree-list-fragment.scss
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ion-list {
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
76
src/app/modules/data/list/tree-list.component.ts
Normal file
76
src/app/modules/data/list/tree-list.component.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {Component, ContentChild, Input, TemplateRef} from '@angular/core';
|
||||||
|
import {DataListContext} from './data-list.component';
|
||||||
|
import {SCThings, SCThingWithoutReferences, SCUuid} from '@openstapps/core';
|
||||||
|
import {Tree, treeGroupBy} from '../../../_helpers/collections/tree-group';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tree-list',
|
||||||
|
templateUrl: 'tree-list.html',
|
||||||
|
styleUrls: ['tree-list.scss'],
|
||||||
|
})
|
||||||
|
export class TreeListComponent {
|
||||||
|
_items?: Promise<SCThings[] | undefined>;
|
||||||
|
|
||||||
|
_groupingKey?: string;
|
||||||
|
|
||||||
|
_groups?: Promise<Tree<SCThings> | undefined>;
|
||||||
|
|
||||||
|
_groupItems?: Record<SCUuid, SCThingWithoutReferences>;
|
||||||
|
|
||||||
|
@Input() set groupingKey(value: keyof SCThings | string | undefined) {
|
||||||
|
this._groupingKey = value;
|
||||||
|
this.groupItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input() set items(items: Promise<SCThings[] | undefined> | undefined) {
|
||||||
|
this._items = items;
|
||||||
|
this.groupItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input() singleType = false;
|
||||||
|
|
||||||
|
@ContentChild(TemplateRef) listItemTemplateRef: TemplateRef<
|
||||||
|
DataListContext<SCThings>
|
||||||
|
>;
|
||||||
|
|
||||||
|
groupItems() {
|
||||||
|
if (!this._items || !this._groupingKey) return;
|
||||||
|
|
||||||
|
this._groups = this._items.then(items => {
|
||||||
|
if (!items || !this._groupingKey) return;
|
||||||
|
|
||||||
|
this._groupItems = {};
|
||||||
|
for (const item of items) {
|
||||||
|
const path = (
|
||||||
|
item as unknown as Record<string, SCThingWithoutReferences[]>
|
||||||
|
)[this._groupingKey];
|
||||||
|
|
||||||
|
for (const pathFragment of path) {
|
||||||
|
this._groupItems[pathFragment.uid] = pathFragment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tree = treeGroupBy(items, item =>
|
||||||
|
(item as unknown as Record<string, SCThingWithoutReferences[]>)[
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
this._groupingKey!
|
||||||
|
].map(thing => thing.uid),
|
||||||
|
);
|
||||||
|
return tree;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/app/modules/data/list/tree-list.html
Normal file
22
src/app/modules/data/list/tree-list.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (C) 2022 StApps
|
||||||
|
~ This program is free software: you can redistribute it and/or modify it
|
||||||
|
~ under the terms of the GNU General Public License as published by the Free
|
||||||
|
~ Software Foundation, version 3.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
~ more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License along with
|
||||||
|
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<tree-list-fragment
|
||||||
|
*ngIf="_groups | async as groups"
|
||||||
|
[items]="groups"
|
||||||
|
[groupMap]="_groupItems"
|
||||||
|
[singleType]="singleType"
|
||||||
|
[listItemTemplateRef]="listItemTemplateRef"
|
||||||
|
></tree-list-fragment>
|
||||||
15
src/app/modules/data/list/tree-list.scss
Normal file
15
src/app/modules/data/list/tree-list.scss
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
Reference in New Issue
Block a user