Skip to content

Commit

Permalink
Contribution dashboard admin change: Add overall item count to contri…
Browse files Browse the repository at this point in the history
…butor dashboard admin stats table (#20186)

* Changes to contributor-dashboard-admin to appear correctly, to reduce number of calls to fetchContributorAdminStats, to subscribe in the correct order

* Add a test to contributor-dashboard-admin unit tests to ensure coverage

* increase coverage of contributor-admin-dashboard page tests

* increase coverage of contributor-admin-dashboard page tests further

* fix e2e test error by reducing elements to 1, as unseen component removed. Removed call to classroom/math as it is no longer added by default.

* remove browser debug

* acl decorator changed to open access for classroom id to name

* fixed classroom linting error

* fixed further linting error in classroom

* fix typescipt check error in contributor-dashboard-admin-stats-backend-api.service test

* fix typescript check failure in contributor-dashboard-admin-stats-backend service

* fix code coverage failure

* removed unnecessary test, and export

* add coverage to contributor dashboard admin test

* Improve test files to make language used more meaningful

* tidied up use of domain constants and expectations of tests

* fixed indentation issue

* merge with develop, includes manuial merge main.py and classroom.py

* finish manual merge of main and classroom

* added tests for userContributionRights, and changed description

* removed extra blank lines from classroom.py

* change headings, simplify html code and move into ts file for unit testing

* Make the calls to contributorDashboardAdminBackendApiService async, and add an await, sop that they complete in order, to prevent a race condition causing overwriting. Change question reveiewer to practice question reviewer

* Call asynchronous method to update question rights from both places

* refactor contributor-admin-stats attributes methods

* Move formatting of contribution attributes in stats table to a service

* Use generics to improve validation and type checking in format-contributor-attributes service, rename some properties

* remove service as a parameter, and unnecessary [] in contributor-dashboard-admin

* Change ordering of parameters for removeContributionReviewerAsync

* Raise toast message when question-admin user tries to use new contribution dashboard admin page

* Add total number of items to contributor-admin-stats-table

* tidy up contribution admin stats for code review

* Refactor contributor dashboard admin for simplicity

* Changed the naming of tests in contributor-dashboard-admin_stats

* tidy up test file for contributor-admin-stats-table
  • Loading branch information
stevenjgodfrey committed May 13, 2024
1 parent 7ab61fb commit ff90095
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ <h2>{{ noDataMessage }}</h2>
</div>
<div class="dashboard-list-header" *ngIf="!loadingMessage && !noDataMessage && isMobileView()">
<div class="dashboard-list-header-count">
<span>Displaying {{ statsPageNumber * itemsPerPage + 1 }} - {{ getUpperLimitValueForPagination() }} of many</span>
<span>Displaying {{ getDisplayedIndexOfFirstItemOnPage() }} - {{ getIndexOfLastItemOnPage() }} of {{getOverallItemCount()}}</span>
</div>
<div class="results-per-page-div">
<span>Results per page: </span>
Expand All @@ -27,7 +27,7 @@ <h2>{{ noDataMessage }}</h2>
</div>
</div>
<table mat-table
[dataSource]="dataSource"
[dataSource]="displayStatsForCurrentPage()"
multiTemplateDataRows
[class.isMobile]="true"
class="mat-elevation-z8 e2e-test-stats-table"
Expand Down Expand Up @@ -171,20 +171,20 @@ <h2>{{ noDataMessage }}</h2>
</table>
<div class="dashboard-list-footer" *ngIf="!loadingMessage && !noDataMessage && !isMobileView()">
<div class="dashboard-list-footer-count">
<span>Displaying {{ statsPageNumber * itemsPerPage + 1 }} - {{ getUpperLimitValueForPagination() }} of many</span>
<span>Displaying {{ getDisplayedIndexOfFirstItemOnPage() }} - {{ getIndexOfLastItemOnPage() }} of {{getOverallItemCount()}}</span>
</div>
<div class="dashboard-list-pagination">
<div>
<i class="fa fa-angle-left stats-pagination-arrow" (click)="navigatePage(MOVE_TO_PREV_PAGE)" *ngIf="statsPageNumber > 0"></i>
<span class="dashboard-list-pagination-value">
<span class="dashboard-list-pagination-active">{{ statsPageNumber + 1 }}</span>
</span>
<i class="fa fa-angle-right stats-pagination-arrow" (click)="navigatePage(MOVE_TO_NEXT_PAGE)" *ngIf="more"></i>
<i class="fa fa-angle-right stats-pagination-arrow" (click)="navigatePage(MOVE_TO_NEXT_PAGE)" *ngIf="tableCanShowMoreItems"></i>
</div>
<div>
<span>Results per page: </span>
<select [(ngModel)]="itemsPerPage" aria-label="Results Per Page" (change)="refreshPagination()">
<option *ngFor="let choice of itemsPerPageChoice" [value]="choice" >{{ choice }}</option>
<select [value]="itemsPerPage" aria-label="Results Per Page" (change)="onItemsPerPageChange($event.target.value); refreshPagination()">
<option *ngFor="let choice of itemsPerPageChoice" [value]="choice">{{ choice }}</option>
</select>
</div>
</div>
Expand All @@ -195,7 +195,7 @@ <h2>{{ noDataMessage }}</h2>
<span class="dashboard-list-pagination-value">
<span class="dashboard-list-pagination-active">{{ statsPageNumber + 1 }}</span>
</span>
<i class="fa fa-angle-right stats-pagination-arrow" (click)="navigatePage(MOVE_TO_NEXT_PAGE)" *ngIf="more"></i>
<i class="fa fa-angle-right stats-pagination-arrow" (click)="navigatePage(MOVE_TO_NEXT_PAGE)" *ngIf="tableCanShowMoreItems"></i>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ import {
} from '../contributor-dashboard-admin-summary.model';

describe('Contributor stats component', () => {
const createQuestionReviewerStats = function createQuestionReviewerStats(
numStats: number
): QuestionReviewerStats[] {
let stats: QuestionReviewerStats[] = [];
for (let i = 0; i < numStats; i++) {
stats.push(questionReviewerStats);
}
return stats;
};
let component: ContributorAdminStatsTable;
let fixture: ComponentFixture<ContributorAdminStatsTable>;
let $window: WindowRef;
Expand Down Expand Up @@ -192,7 +201,7 @@ describe('Contributor stats component', () => {
};
component.inputs.activeTab = component.TAB_NAME_TRANSLATION_SUBMITTER;
component.ngOnChanges(changes);
component.updateColumnsToDisplay();
component.displayContributorAdminStats();
tick();
expect(component.columnsToDisplay).toEqual([
'chevron',
Expand Down Expand Up @@ -226,7 +235,7 @@ describe('Contributor stats component', () => {
};
component.inputs.activeTab = component.TAB_NAME_TRANSLATION_REVIEWER;
component.ngOnChanges(changes);
component.updateColumnsToDisplay();
component.displayContributorAdminStats();
tick();
expect(component.columnsToDisplay).toEqual([
'chevron',
Expand Down Expand Up @@ -258,7 +267,7 @@ describe('Contributor stats component', () => {
};
component.inputs.activeTab = component.TAB_NAME_QUESTION_SUBMITTER;
component.ngOnChanges(changes);
component.updateColumnsToDisplay();
component.displayContributorAdminStats();
tick();
expect(component.columnsToDisplay).toEqual([
'chevron',
Expand All @@ -269,6 +278,7 @@ describe('Contributor stats component', () => {
'lastContributedInDays',
'role',
]);
expect(component.getOverallItemCount()).toEqual('1');
}));

it('should show question reviewer stats', fakeAsync(() => {
Expand All @@ -279,7 +289,7 @@ describe('Contributor stats component', () => {
Promise.resolve({
stats: [questionReviewerStats],
nextOffset: 1,
more: false,
more: true,
} as QuestionReviewerStatsData)
);
const changes: SimpleChanges = {
Expand All @@ -292,7 +302,7 @@ describe('Contributor stats component', () => {
};
component.inputs.activeTab = component.TAB_NAME_QUESTION_REVIEWER;
component.ngOnChanges(changes);
component.updateColumnsToDisplay();
component.displayContributorAdminStats();
tick();
expect(component.columnsToDisplay).toEqual([
'chevron',
Expand All @@ -301,16 +311,64 @@ describe('Contributor stats component', () => {
'lastContributedInDays',
'role',
]);
expect(component.getOverallItemCount()).toEqual('1+');
}));

it('should check for upperlimit for pagination', fakeAsync(() => {
component.dataSource = [];
component.statsPageNumber = 1;
it(
'should index last item on page as "overall item count" when ' +
'"current page\'s cumulative item count"' +
' exceeds "overall item count".',
fakeAsync(() => {
component.statsPageNumber = 1;
component.itemsPerPage = 4;
fixture.detectChanges();
component.allStats = createQuestionReviewerStats(3);
expect(component.getIndexOfLastItemOnPage()).toEqual(3);
})
);

it(
'should index last item on page as "current page\'s ' +
'cumulative item count" when "overall item count"' +
' exceeds "current page\'s cumulative item count".',
fakeAsync(() => {
component.statsPageNumber = 1;
component.itemsPerPage = 1;
fixture.detectChanges();
component.allStats = createQuestionReviewerStats(3);
expect(component.getIndexOfLastItemOnPage()).toEqual(2);
})
);

it('should retrieve the index of the first item on the page', fakeAsync(() => {
component.statsPageNumber = 2;
component.itemsPerPage = 3;
expect(component.getDisplayedIndexOfFirstItemOnPage()).toEqual(7);
}));

it('should show the overall item count from the number of items', fakeAsync(() => {
component.statsPageNumber = 1;
component.itemsPerPage = 1;
fixture.detectChanges();
expect(component.getUpperLimitValueForPagination()).toEqual(3);
component.allStats = createQuestionReviewerStats(3);
expect(component.getOverallItemCount()).toEqual(
component.allStats.length.toString()
);
}));

it(
'should show a "+" at the end of the overall item count when ' +
'the number of items exceeds max expected',
fakeAsync(() => {
component.statsPageNumber = 1;
component.itemsPerPage = 1;
component.tableHasMoreThanMaximumExpectedItems = true;
fixture.detectChanges();
component.allStats = createQuestionReviewerStats(1000);
expect(component.getOverallItemCount()).toEqual('1000+');
})
);

it('should navigate to next page', fakeAsync(() => {
const goToSpy = spyOn(component, 'goToPageNumber');
component.statsPageNumber = 1;
Expand Down Expand Up @@ -357,7 +415,7 @@ describe('Contributor stats component', () => {
};
component.inputs.activeTab = component.TAB_NAME_TRANSLATION_SUBMITTER;
component.ngOnChanges(changes);
component.updateColumnsToDisplay();
component.displayContributorAdminStats();
tick();
expect(component.columnsToDisplay).toEqual([
'contributorName',
Expand Down Expand Up @@ -391,7 +449,7 @@ describe('Contributor stats component', () => {
};
component.inputs.activeTab = component.TAB_NAME_TRANSLATION_REVIEWER;
component.ngOnChanges(changes);
component.updateColumnsToDisplay();
component.displayContributorAdminStats();
tick();
expect(component.columnsToDisplay).toEqual([
'contributorName',
Expand Down Expand Up @@ -423,7 +481,7 @@ describe('Contributor stats component', () => {
};
component.inputs.activeTab = component.TAB_NAME_QUESTION_SUBMITTER;
component.ngOnChanges(changes);
component.updateColumnsToDisplay();
component.displayContributorAdminStats();
tick();
expect(component.columnsToDisplay).toEqual([
'contributorName',
Expand Down Expand Up @@ -457,7 +515,7 @@ describe('Contributor stats component', () => {
};
component.inputs.activeTab = component.TAB_NAME_QUESTION_REVIEWER;
component.ngOnChanges(changes);
component.updateColumnsToDisplay();
component.displayContributorAdminStats();
tick();
expect(component.columnsToDisplay).toEqual([
'contributorName',
Expand Down Expand Up @@ -844,5 +902,47 @@ describe('Contributor stats component', () => {
activeTab = component.TAB_NAME_QUESTION_REVIEWER;
expect(component.getContributionCount(activeTab, 1, 2, 3, 4)).toEqual(4);
}));

it('should convert the items per page dropdown back into numbers', fakeAsync(() => {
component.onItemsPerPageChange('05');
expect(component.itemsPerPage).toEqual(5);
}));
});

describe('when more than one page of stats are returned', () => {
it('should show data on multiple pages', fakeAsync(() => {
let allQuestionReviewerStats: QuestionReviewerStats[] =
createQuestionReviewerStats(30);

spyOn(
contributorDashboardAdminStatsBackendApiService,
'fetchContributorAdminStats'
).and.returnValue(
Promise.resolve({
stats: allQuestionReviewerStats,
nextOffset: 1,
more: false,
} as QuestionReviewerStatsData)
);
const changes: SimpleChanges = {
activeTab: {
currentValue: component.TAB_NAME_QUESTION_REVIEWER,
previousValue: component.TAB_NAME_QUESTION_SUBMITTER,
firstChange: false,
isFirstChange: () => false,
},
};
component.inputs.activeTab = component.TAB_NAME_QUESTION_REVIEWER;
component.ngOnChanges(changes);

tick();
expect(component.getOverallItemCount()).toEqual('30');
expect(component.displayStatsForCurrentPage().length).toEqual(20);
expect(component.tableCanShowMoreItems).toEqual(true);

component.goToPageNumber(1);
expect(component.displayStatsForCurrentPage().length).toEqual(10);
expect(component.tableCanShowMoreItems).toEqual(false);
}));
});
});
Loading

0 comments on commit ff90095

Please sign in to comment.