Skip to content

Commit c137025

Browse files
authored
Merge pull request #3533 from alfonso-salces/MOBILE-4077
Mobile 4077 - Support user custom reports
2 parents 4b6926e + 7b37a90 commit c137025

File tree

22 files changed

+1362
-0
lines changed

22 files changed

+1362
-0
lines changed

scripts/langindex.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,12 @@
16521652
"core.courses.totalcoursesearchresults": "local_moodlemobileapp",
16531653
"core.currentdevice": "local_moodlemobileapp",
16541654
"core.custom": "form",
1655+
"core.reportbuilder.modifiedby": "tool_reportbuilder",
1656+
"core.reportbuilder.reportstab": "tool_reportbuilder",
1657+
"core.reportbuilder.reportsource": "tool_reportbuilder",
1658+
"core.reportbuilder.timecreated": "tool_reportbuilder",
1659+
"core.reportbuilder.showcolumns": "local_moodlemobileapp",
1660+
"core.reportbuilder.hidecolumns": "local_moodlemobileapp",
16551661
"core.datastoredoffline": "local_moodlemobileapp",
16561662
"core.date": "moodle",
16571663
"core.datecreated": "repository",

src/core/features/features.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { CoreUserModule } from './user/user.module';
4343
import { CoreUserToursModule } from './usertours/user-tours.module';
4444
import { CoreViewerModule } from './viewer/viewer.module';
4545
import { CoreXAPIModule } from './xapi/xapi.module';
46+
import { CoreReportBuilderModule } from './reportbuilder/reportbuilder.module';
4647

4748
@NgModule({
4849
imports: [
@@ -74,6 +75,7 @@ import { CoreXAPIModule } from './xapi/xapi.module';
7475
CoreUserToursModule,
7576
CoreViewerModule,
7677
CoreXAPIModule,
78+
CoreReportBuilderModule,
7779

7880
// Import last to allow overrides.
7981
CoreEmulatorModule,
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// (C) Copyright 2015 Moodle Pty Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { CoreRoutedItemsManagerSource } from '@classes/items-management/routed-items-manager-source';
16+
import { CoreReportBuilder, CoreReportBuilderReport, REPORTS_LIST_LIMIT } from '../services/reportbuilder';
17+
18+
/**
19+
* Provides a list of reports.
20+
*/
21+
export class CoreReportBuilderReportsSource extends CoreRoutedItemsManagerSource<CoreReportBuilderReport> {
22+
23+
/**
24+
* @inheritdoc
25+
*/
26+
getItemPath(report: CoreReportBuilderReport): string {
27+
return report.id.toString();
28+
}
29+
30+
/**
31+
* @inheritdoc
32+
*/
33+
protected async loadPageItems(page: number): Promise<{ items: CoreReportBuilderReport[]; hasMoreItems: boolean }> {
34+
const reports = await CoreReportBuilder.getReports(page, this.getPageLength());
35+
36+
return { items: reports, hasMoreItems: reports.length > 0 };
37+
}
38+
39+
/**
40+
* @inheritdoc
41+
*/
42+
protected setItems(reports: CoreReportBuilderReport[], hasMoreItems: boolean): void {
43+
const sortedReports = reports.slice(0);
44+
reports.sort((a, b) => a.timecreated < b.timecreated ? 1 : -1);
45+
super.setItems(sortedReports, hasMoreItems);
46+
}
47+
48+
/**
49+
* @inheritdoc
50+
*/
51+
protected getPageLength(): number {
52+
return REPORTS_LIST_LIMIT;
53+
}
54+
55+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// (C) Copyright 2015 Moodle Pty Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { NgModule } from '@angular/core';
16+
import { CoreSharedModule } from '@/core/shared.module';
17+
import { CoreReportBuilderReportColumnComponent } from './report-column/report-column';
18+
import { CoreReportBuilderReportDetailComponent } from './report-detail/report-detail';
19+
import { CoreReportBuilderReportSummaryComponent } from './report-summary/report-summary';
20+
21+
@NgModule({
22+
imports: [
23+
CoreSharedModule,
24+
],
25+
declarations: [
26+
CoreReportBuilderReportDetailComponent,
27+
CoreReportBuilderReportColumnComponent,
28+
CoreReportBuilderReportSummaryComponent,
29+
],
30+
exports: [
31+
CoreReportBuilderReportDetailComponent,
32+
CoreReportBuilderReportColumnComponent,
33+
CoreReportBuilderReportSummaryComponent,
34+
],
35+
})
36+
export class CoreReportBuilderComponentsModule {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<ion-item class="ion-text-wrap" lines="inset" [detail]="false" [button]="isExpandable" [attr.aria-expanded]="isExpanded"
2+
[attr.aria-controls]="'core-report-builder-column-' + rowIndex"
3+
[attr.aria-label]="(isExpanded ? 'core.hidecolumns' : 'core.showcolumns') | translate" (click)="toggleRow()">
4+
<ion-label>
5+
<h3 *ngIf="columnIndex !== 0 || (columnIndex === 0 && showFirstTitle)"> {{ header }} </h3>
6+
<core-format-text [text]="column" contextLevel="site" [contextInstanceId]="contextId"></core-format-text>
7+
</ion-label>
8+
<ion-icon [class.expandable-status-icon-expanded]="!isExpanded" slot="end" aria-hidden="true" name="fas-chevron-up"
9+
class="expandable-status-icon" *ngIf="isExpandable" flip-rtl>
10+
</ion-icon>
11+
</ion-item>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@import "~theme/globals";
2+
3+
:host {
4+
--rotate-expandable: rotate(180deg);
5+
6+
.expandable-status-icon {
7+
font-size: var(--text-size);
8+
@include margin-horizontal(0, 2px);
9+
@include core-transition(transform, 200ms);
10+
}
11+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// (C) Copyright 2015 Moodle Pty Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { Component, EventEmitter, Input, Output } from '@angular/core';
16+
17+
@Component({
18+
selector: 'core-report-builder-report-column',
19+
templateUrl: './report-column.html',
20+
styleUrls: ['./report-column.scss'],
21+
})
22+
export class CoreReportBuilderReportColumnComponent {
23+
24+
@Input() isExpanded = false;
25+
@Input() isExpandable = false;
26+
@Input() showFirstTitle = false;
27+
@Input() columnIndex!: number;
28+
@Input() rowIndex!: number;
29+
@Input() column!: string;
30+
@Input() contextId!: number;
31+
@Input() header!: string;
32+
@Output() onToggleRow: EventEmitter<number> = new EventEmitter();
33+
34+
/**
35+
* Emits row click
36+
*/
37+
toggleRow(): void {
38+
this.onToggleRow.emit(this.rowIndex);
39+
}
40+
41+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<ng-container *ngIf="state$ | async as state">
2+
3+
<core-loading [hideUntil]="state.loaded">
4+
5+
<ng-container *ngIf="state.report?.data?.rows && state.report?.data?.headers && state.report?.details; else empty">
6+
7+
<ion-refresher slot="fixed" [disabled]="!state.loaded" (ionRefresh)="refreshReport($event.target)">
8+
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
9+
</ion-refresher>
10+
11+
<ng-container *ngIf="isCardLayout">
12+
<ion-card *ngFor="let row of state.report.data.rows; let rowIndex = index">
13+
<ion-list class="ion-text-wrap">
14+
<core-report-builder-report-column *ngFor="let column of row.columns | slice:0:row.isExpanded ?
15+
row.columns.length : state.cardVisibleColumns; let columnIndex = index" [columnIndex]="columnIndex"
16+
[rowIndex]="rowIndex" [isExpandable]="columnIndex === 0 && row.columns.length > state.cardVisibleColumns"
17+
[isExpanded]="row.isExpanded" [showFirstTitle]="state.cardviewShowFirstTitle"
18+
[contextId]="state.report.details.contextid" [header]="state.report.data.headers[columnIndex]" [column]="column"
19+
(onToggleRow)="toggleRow(rowIndex)">
20+
</core-report-builder-report-column>
21+
</ion-list>
22+
</ion-card>
23+
</ng-container>
24+
25+
<ng-container *ngIf="!isCardLayout">
26+
<table>
27+
<thead>
28+
<tr>
29+
<th *ngFor="let header of state.report.data.headers">
30+
{{ header }}
31+
</th>
32+
</tr>
33+
</thead>
34+
<tbody>
35+
<tr *ngFor="let row of state.report.data.rows">
36+
<td *ngFor="let column of row.columns">
37+
<core-format-text [text]="column" [contextLevel]="'site'"
38+
[contextInstanceId]="state.report.details.contextid">
39+
</core-format-text>
40+
</td>
41+
</tr>
42+
</tbody>
43+
</table>
44+
</ng-container>
45+
46+
</ng-container>
47+
48+
<ng-template #empty>
49+
<core-empty-box *ngIf="!state.report?.data?.rows || !state.report?.data?.headers || !state.report?.details" icon="fa-list-alt"
50+
[message]="'core.course.nocontentavailable' | translate"></core-empty-box>
51+
</ng-template>
52+
53+
<core-infinite-loading *ngIf="!isBlock && state.report?.data?.rows && state.report?.data?.headers && state.report?.details"
54+
[enabled]="state.canLoadMoreRows" (action)="fetchMoreInfo($event)" [error]="state.errorLoadingRows">
55+
</core-infinite-loading>
56+
57+
58+
</core-loading>
59+
60+
</ng-container>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
@import "~theme/globals";
2+
3+
:host {
4+
--header-background: var(--white);
5+
--border-color: var(--stroke);
6+
7+
.report-title {
8+
ion-item {
9+
width: 100%;
10+
}
11+
}
12+
13+
table {
14+
width: 98%;
15+
margin: 1em auto;
16+
border-collapse: collapse;
17+
color: var(--ion-text-color);
18+
overflow-x: auto;
19+
display: block;
20+
21+
tbody {
22+
display: table;
23+
}
24+
25+
th {
26+
background-color: var(--header-background);
27+
}
28+
29+
tr {
30+
border-bottom: 1px solid var(--border-color);
31+
32+
&:nth-child(even) {
33+
background: var(--light);
34+
}
35+
}
36+
37+
th, td {
38+
@include padding(8px, 8px, 8px, null);
39+
text-align: start;
40+
min-width: 200px;
41+
}
42+
43+
}
44+
}

0 commit comments

Comments
 (0)