Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show more relevant info for teachers on course cards #4299

Merged
merged 40 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b46609e
Mockup of teacher stats
jorg-vr Jan 5, 2023
8f6f863
Teacher homepage cards mockup
jorg-vr Jan 6, 2023
95250ad
Merge branch 'feature/rethink-course-cards' into feature/teacher-cour…
jorg-vr Jan 16, 2023
5b1fe4e
Cleaner stats
jorg-vr Jan 16, 2023
3abc1f9
Always show 3 items
jorg-vr Jan 16, 2023
8829e6a
Find series being worked on
jorg-vr Jan 16, 2023
09c9375
Merge branch 'feature/rethink-course-cards' into feature/teacher-cour…
jorg-vr Jan 16, 2023
9b32d9c
Never show exercises for teachers
jorg-vr Jan 16, 2023
4c0524a
Show closed series to course admins
jorg-vr Jan 17, 2023
9b7d450
Add notification for incomplete feedbacks
jorg-vr Jan 17, 2023
c13acc6
Put admin notifications inside a method
jorg-vr Jan 17, 2023
03c4e6e
Add empty state
jorg-vr Jan 17, 2023
8fa18fc
Fix linting
jorg-vr Jan 17, 2023
4ebcf6e
Merge branch 'develop' into feature/teacher-course-cards
jorg-vr Jan 18, 2023
a83570f
Improve add series option
jorg-vr Jan 18, 2023
ecbb1be
Don't color deadlines for teachers
jorg-vr Jan 18, 2023
533021f
Minor fixes
jorg-vr Jan 18, 2023
97c9d8d
Add series count and tooltips
jorg-vr Jan 18, 2023
a9364ba
Color icons
jorg-vr Jan 18, 2023
81391dd
Make the texts nicer
jorg-vr Jan 18, 2023
88185b3
Speed up calculation of most recent series
jorg-vr Jan 19, 2023
e3a5f59
Fix title appearing twize bug
jorg-vr Jan 19, 2023
d619dd1
Fix zoomed in dots bug
jorg-vr Jan 19, 2023
ba47285
Change feedback translation
jorg-vr Jan 19, 2023
2c8e011
Test series being worked on
jorg-vr Jan 19, 2023
5c1c85e
Test admin notifications
jorg-vr Jan 19, 2023
d489d2e
TEst series users by number of completed activities
jorg-vr Jan 19, 2023
0025490
Don't show icons for open for institution
jorg-vr Jan 19, 2023
9c49e83
Only teacher should see hidden deadlines
jorg-vr Jan 19, 2023
9f9bd9c
Always the same series icon for teachers
jorg-vr Jan 20, 2023
63bc06c
Improve feedback translations
jorg-vr Jan 20, 2023
fc06e16
No end dots for help texts
jorg-vr Jan 20, 2023
8e0cc20
Remove use of Current.user
jorg-vr Jan 20, 2023
a0fe7e7
Make course admin notifications a helper
jorg-vr Jan 20, 2023
74764f9
Get rid of inline styles
jorg-vr Jan 20, 2023
a341cf5
Apply suggestions from code review
jorg-vr Jan 20, 2023
b103169
Merge branch 'develop' into feature/teacher-course-cards
jorg-vr Jan 20, 2023
9d58412
Add progress bar to homepage
jorg-vr Jan 20, 2023
48d9403
More spacing in header
jorg-vr Jan 20, 2023
6002477
Fix margin
jorg-vr Jan 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions app/assets/javascripts/components/loading_bar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { html, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ShadowlessLitElement } from "components/shadowless_lit_element";
import { searchQuery } from "search";

/**
* This component represents a loading bar.
* It will be triggered by search
*
* @element d-loading-bar
*/
@customElement("d-loading-bar")
export class LoadingBar extends ShadowlessLitElement {
@property({ type: Boolean, state: true })
loading = false;

constructor() {
super();
searchQuery.loadingBars.push(this);
}

show(): void {
this.loading = true;
}

hide(): void {
this.loading = false;
}

render(): TemplateResult {
return html`
<div class="dodona-progress dodona-progress-indeterminate" style="visibility: ${this.loading ? "visible" : "hidden"};">
<div class="progressbar bar bar1" style="width: 0%;"></div>
<div class="bufferbar bar bar2" style="width: 100%;"></div>
<div class="auxbar bar bar3" style="width: 0%;"></div>
</div>
`;
}
}
63 changes: 63 additions & 0 deletions app/assets/javascripts/components/progress_bar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { html, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ShadowlessLitElement } from "components/shadowless_lit_element";
import { initTooltips, ready } from "util.js";

/**
* This component displays a progress bar consisting of consecutive divs
* The divs are scaled according to the given values
* The divs have an opacity according to their index
*
* @element d-progress-bar
*
* @prop {number[]} values - Pass the data as an array.
* @prop {string} titleKey - The key of the title to be displayed in the tooltip.
*/
@customElement("d-progress-bar")
export class ProgressBar extends ShadowlessLitElement {
@property({ type: Array })
values: Array<number>;

@property({ type: String, attribute: "title-key" })
titleKey: string;

get valuesSum(): number {
return Object.values(this.values).reduce((a, b) => a + b, 0);
}

private getWidth(value: number): number {
return 100 * value / this.valuesSum;
}

private getOpacity(key: number): number {
return (key / (this.values.length - 1)) * 0.8 + 0.2;
}

private getTitle(value: number, index: number): string {
return I18n.t(this.titleKey + I18n.t(this.titleKey + ".key", index), { index: index, smart_count: value });
}

updated(changedProperties: Map<string, any>): void {
initTooltips(this);
super.updated(changedProperties);
}

constructor() {
super();
// Reload when I18n is available
ready.then(() => this.requestUpdate());
}

private renderBar(value: number, index: number): TemplateResult {
return html`<div
class="bar"
style="width: ${this.getWidth(value)}%; opacity: ${this.getOpacity(index)}; "
title=${this.getTitle(value, index)}
data-bs-toggle='tooltip'>
</div>`;
}

render(): TemplateResult[] {
return this.values.map( (v, i) => this.renderBar(v, i)).reverse();
}
}
6 changes: 6 additions & 0 deletions app/assets/javascripts/i18n/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ export class I18n extends Polyglot {
}
}

constructor() {
super();
// set default locale, avoids a lot of errors when the locale is not yet set
this.locale = "en";
}

get locale(): string {
return super.locale();
}
Expand Down
14 changes: 14 additions & 0 deletions app/assets/javascripts/i18n/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,13 @@
"no_selection": "You must select at least one item before being able to download solutions.",
"options": "Options",
"programming_languages": "Programming Languages",
"progress_bar": {
"series-admin-progress": {
"key": ".singular |||| .plural",
"plural": "One user has completed %{index} activities |||| %{smart_count} users have completed %{index} activities",
"singular": "One user has completed one activity |||| %{smart_count} users have completed one activity"
}
},
"question": {
"state": {
"answered": "Answered",
Expand Down Expand Up @@ -709,6 +716,13 @@
"no_selection": "Er moet ten minste één iets gekozen worden om oplossingen te kunnen downloaden.",
"options": "Opties",
"programming_languages": "Programmeertalen",
"progress_bar": {
"series-admin-progress": {
"key": ".singular |||| .plural",
"plural": "Eén gebruiker heeft %{index} oefeningen correct opgelost |||| %{smart_count} gebruikers hebben %{index} oefeningen correct opgelost",
"singular": "Eén gebruiker heeft één oefening correct opgelost |||| %{smart_count} gebruikers hebben één oefening correct opgelost"
}
},
"question": {
"state": {
"answered": "Beantwoord",
Expand Down
12 changes: 4 additions & 8 deletions app/assets/javascripts/search.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createDelayer, fetch, getURLParameter, updateArrayURLParameter, updateURLParameter } from "util.js";
import { InactiveTimeout } from "auto_reload";
import { LoadingBar } from "components/loading_bar";
const RELOAD_SECONDS = 2;


Expand Down Expand Up @@ -56,6 +57,7 @@ export class SearchQuery {
arrayQueryParams: QueryParameters<string[]> = new QueryParameters<string[]>();
queryParams: QueryParameters<string> = new QueryParameters<string>();
localStorageKey?: string;
loadingBars: LoadingBar[] = [];

setRefreshElement(refreshElement: string): void {
this.refreshElement = refreshElement;
Expand Down Expand Up @@ -180,7 +182,7 @@ export class SearchQuery {
const url = this.addParametersToUrl();
const localIndex = ++this.searchIndex;

this.updateProgressFilterVisibility("visible");
this.loadingBars.forEach(bar => bar.show());
fetch(updateURLParameter(url, "format", "js"), {
headers: {
"accept": "text/javascript"
Expand All @@ -193,7 +195,7 @@ export class SearchQuery {
this.appliedIndex = localIndex;
eval(data);
}
this.updateProgressFilterVisibility("hidden");
this.loadingBars.forEach(bar => bar.hide());

// if there is local storage key => update the value to reuse later
if (this.localStorageKey) {
Expand All @@ -203,12 +205,6 @@ export class SearchQuery {
});
}

updateProgressFilterVisibility(state: string): void {
if (document.getElementById("progress-filter")) {
document.getElementById("progress-filter").style.visibility = state;
}
}

/**
* fetch params from localStorage using the localStorageKey if present and apply them to the current url
*/
Expand Down
13 changes: 10 additions & 3 deletions app/assets/javascripts/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,22 @@ async function initCSRF() {
});
}

function initTooltips() {
function initTooltips(root = document) {
// First remove dead tooltips
const tooltips = document.querySelectorAll(".tooltip");
const tooltips = root.querySelectorAll(".tooltip");
for (const tooltip of tooltips) {
tooltip.remove();
}

// Then reinitialize tooltips
$("[data-bs-toggle=\"tooltip\"]").tooltip({ container: "body", trigger: "hover" });
const elements = root.querySelectorAll("[data-bs-toggle=\"tooltip\"]");
for (const element of elements) {
const tooltip = window.bootstrap.Tooltip.getOrCreateInstance(element);
if (element.title) {
tooltip.setContent({ ".tooltip-inner": element.title });
element.removeAttribute("title");
}
}
}

function tooltip(target, message, disappearAfter=1000) {
Expand Down
10 changes: 10 additions & 0 deletions app/assets/stylesheets/base.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@
color: $info;
}

.colored-secondary {
color: $secondary;
}

figcaption {
margin: 0 10px;
}
Expand All @@ -110,3 +114,9 @@ svg {
--svg-color-incorrect: #{$danger};
--svg-color-warning: #{$warning};
}

.spread-line {
display: flex;
justify-content: space-between;
flex-direction: row;
}
1 change: 1 addition & 0 deletions app/assets/stylesheets/components.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
@import "components/dropdown-filter.css.scss";
@import "components/courselabel-edit.css.scss";
@import "components/action-card.css.scss";
@import "components/progress_bar.css.scss";

.flex-spacer {
flex-grow: 1;
Expand Down
12 changes: 6 additions & 6 deletions app/assets/stylesheets/components/action-card.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@
small {
font-size: 65%;
}

.spread-line {
display: flex;
justify-content: space-between;
flex-direction: row;
}
}

.card-title-icon {
Expand Down Expand Up @@ -57,6 +51,12 @@
--progress-chart-color: var(--on-clickable-card-color);
}

d-progress-bar {
.bar {
background-color: var(--on-clickable-card-color);
}
}

&:hover,
&:focus,
&:active {
Expand Down
9 changes: 9 additions & 0 deletions app/assets/stylesheets/components/card.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ $card-supporting-text-padding: 16px;
.progress-chart.colored-muted {
--progress-chart-color: #{$on-primary-container};
}

.series-icon {
--icon-color: #{$on-primary-container};
--icon-background-color: #{$primary-container};
}
}

.home-summary-card.course .card-title {
height: 111px;
}

a.card-title-link,
Expand Down
9 changes: 9 additions & 0 deletions app/assets/stylesheets/components/progress_bar.css.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
d-progress-bar {
display: block;

.bar {
height: 8px;
display: inline-block;
background-color: $success;
}
}
35 changes: 3 additions & 32 deletions app/assets/stylesheets/components/table-toolbar.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -102,19 +102,13 @@
}

.dodona-progress > .progressbar {
background-color: $progress-bar-bg;
background-color: $on-secondary-container;
z-index: 1;
left: 0;
}

.dodona-progress > .bufferbar {
background-image:
linear-gradient(
to right,
rgba(255, 255, 255, 0.7),
rgba(255, 255, 255, 0.7)
),
linear-gradient(to right, $secondary, $secondary);
background-color: $secondary-container;
z-index: 0;
left: 0;
}
Expand All @@ -125,17 +119,12 @@

.dodona-progress.dodona-progress-indeterminate > .bar1,
.dodona-progress.dodona-progress-indeterminate > .bar3 {
background-color: $progress-bar-bg;
background-color: $on-secondary-container;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}

.mdl-progress.mdl-progress-indeterminate > .bar3 {
background-image: none;
animation-name: indeterminate2;
}

.dodona-progress.dodona-progress-indeterminate > .bar1 {
animation-name: indeterminate1;
}
Expand All @@ -156,21 +145,3 @@
width: 0%;
}
}

@keyframes indeterminate2 {
0%,
50% {
left: 0%;
width: 0%;
}

75% {
left: 0%;
width: 25%;
}

100% {
left: 100%;
width: 0%;
}
}
4 changes: 4 additions & 0 deletions app/assets/stylesheets/material_icons.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
line-height: 74px;
}

.mdi.mdi-vam::before {
vertical-align: middle;
}

.visible-xs.mdi::before {
margin-top: 12px;
}
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def home
@year = params[:year] || @years.max
@courses = courses.select { |c| c.year == @year }
@favorite_courses = course_memberships.select(&:favorite).map(&:course)
@homepage_series = courses.map { |c| c.homepage_series(0) }.flatten.sort_by(&:deadline)
@homepage_series = courses.map { |c| c.homepage_series(current_user, 0) }.flatten.sort_by(&:deadline)

@jump_back_in = current_user.jump_back_in
else
Expand Down
Loading