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

Introduce editable table for creating score distributions #5723

Merged
merged 66 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
2ea4fd5
DIY first version
jorg-vr Aug 6, 2024
935ce06
Use jspreadsheet
jorg-vr Aug 6, 2024
0df802b
Disable unwanted options
jorg-vr Aug 7, 2024
afee968
Actually save updates
jorg-vr Aug 7, 2024
f6f7f81
Fix new rows
jorg-vr Aug 7, 2024
e45df51
Allow inserting in different order
jorg-vr Aug 7, 2024
94161d2
Add validation
jorg-vr Aug 7, 2024
6258c97
Delete no longer needed options
jorg-vr Aug 7, 2024
c1e43df
Fix toggle
jorg-vr Aug 7, 2024
e516a08
Introduce translations
jorg-vr Aug 8, 2024
4e8e4c9
Introduce translations
jorg-vr Aug 8, 2024
0ddc92a
Add help text
jorg-vr Aug 8, 2024
4d99358
Fix minor bugs
jorg-vr Aug 8, 2024
a52eeff
Show validation warning
jorg-vr Aug 8, 2024
2812c8d
Ask to confirm warnings
jorg-vr Aug 8, 2024
abadbe9
Improve buttons
jorg-vr Aug 8, 2024
2a0a4a8
Remove checkboxes
jorg-vr Aug 8, 2024
40d20f9
Fix row heights
jorg-vr Aug 8, 2024
99b27c8
Merge branch 'main' into feat/table-input
jorg-vr Aug 8, 2024
61ed540
Fix tests
jorg-vr Aug 8, 2024
66c5247
Remove system test
jorg-vr Aug 8, 2024
2451a67
Fix empty case
jorg-vr Aug 8, 2024
c68b4d0
Judge empty rows more kindly
jorg-vr Aug 8, 2024
ad5c0d8
Remove the export option
jorg-vr Aug 8, 2024
defc89e
Avoid type coercion
jorg-vr Aug 9, 2024
41d8fae
Remove comments
jorg-vr Aug 9, 2024
bf47ad7
Add docs
jorg-vr Aug 9, 2024
973371d
Add translations for menu
jorg-vr Aug 9, 2024
a7e363d
Fix dark mode
jorg-vr Aug 9, 2024
f1ac12c
Merge branch 'main' into feat/table-input
jorg-vr Aug 30, 2024
be2eec6
Merge branch 'main' into feat/table-input
jorg-vr Oct 25, 2024
838e3cc
Open edit table on click
jorg-vr Oct 25, 2024
88d9bb4
Align colums left as in non edit version
jorg-vr Oct 25, 2024
370b371
Remove outline of btn
jorg-vr Oct 25, 2024
cc50615
Change header text style
jorg-vr Oct 25, 2024
d443fa0
Improve number validation
jorg-vr Oct 25, 2024
5cb4711
Update warnings
jorg-vr Oct 25, 2024
56982a5
Fix paste in chrome
jorg-vr Oct 28, 2024
cc80dde
Update app/assets/javascripts/components/input_table.ts
jorg-vr Oct 28, 2024
26951de
Merge branch 'main' into feat/table-input
jorg-vr Nov 13, 2024
b26e13a
Fix clickability of max score column
jorg-vr Nov 13, 2024
8352cf2
Merge branch 'main' into feat/table-input
jorg-vr Nov 18, 2024
19706ee
Make cursor point out edditable
jorg-vr Nov 18, 2024
5b72d72
Use text button for edit
jorg-vr Nov 18, 2024
c47f7ce
Add button to empty state
jorg-vr Nov 18, 2024
0aef455
Add delete row button functionality
jorg-vr Nov 18, 2024
d5ab37c
Add title to delete button
jorg-vr Nov 18, 2024
e178e01
Fix checkboxes
jorg-vr Nov 19, 2024
ecaff9e
Remove error text on cancel
jorg-vr Nov 19, 2024
d8e26d0
Get rid of red squibles
jorg-vr Nov 19, 2024
7973375
fix spelling
jorg-vr Nov 19, 2024
c3515e3
Fix colspan
jorg-vr Nov 19, 2024
fe65e92
Update app/assets/javascripts/components/input_table.ts
jorg-vr Nov 20, 2024
19929b8
Fix checkbox allignment in chrome
jorg-vr Nov 26, 2024
bf5db5f
Add visble score checkbox to form
jorg-vr Dec 2, 2024
72fa0d6
Remove score items controller
jorg-vr Dec 2, 2024
3dcd370
Remove invalid comment
jorg-vr Dec 2, 2024
a54a12c
Add translation
jorg-vr Dec 3, 2024
603badf
Improve translation
jorg-vr Dec 3, 2024
4bcb038
Finish removel of unused files
jorg-vr Dec 3, 2024
2d68059
Create new button style
jorg-vr Dec 3, 2024
6c92116
Make whole tabele edditable
jorg-vr Dec 3, 2024
bac9153
Remove explicit edit button
jorg-vr Dec 3, 2024
2524323
Fix linting
jorg-vr Dec 3, 2024
9ee2ed9
Make grey button become darker
jorg-vr Dec 9, 2024
82a1b6c
Always show add score items button
jorg-vr Dec 9, 2024
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
333 changes: 333 additions & 0 deletions app/assets/javascripts/components/input_table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
import { customElement, property } from "lit/decorators.js";
import { html, PropertyValues, render, TemplateResult } from "lit";
import jspreadsheet, { CellValue, Column, CustomEditor, JspreadsheetInstance } from "jspreadsheet-ce";
import { createRef, ref, Ref } from "lit/directives/ref.js";
import { DodonaElement } from "components/meta/dodona_element";
import { fetch, ready } from "utilities";
import { i18n } from "i18n/i18n";
import { Tooltip } from "bootstrap";
import { watchMixin } from "components/meta/watch_mixin";

Check warning on line 9 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L1-L9

Added lines #L1 - L9 were not covered by tests

type CellData = string | number | boolean;
type ScoreItem = {
id: number | null;
name: string;
description?: string;
maximum: string;
visible: boolean;
order?: number;
}

type ColumnWithTooltip = Column & { tooltip?: string };

const toBoolean = (value: CellValue): boolean => {

Check warning on line 23 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L23

Added line #L23 was not covered by tests
return value === "true" || value === true;
};

/**
* A spreadsheet table to edit score items.
*
* @element d-score-item-input-table
*
* @fires cancel - When the cancel button is clicked.
*
* @prop {string} route - The route to send the updated score items to.
* @prop {ScoreItem[]} scoreItems - The original score items, that will be displayed in the table.
*/
@customElement("d-score-item-input-table")
export class ScoreItemInputTable extends watchMixin(DodonaElement) {

Check warning on line 38 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L38

Added line #L38 was not covered by tests
@property({ type: String })
route: string = "";

Check warning on line 40 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L40

Added line #L40 was not covered by tests
@property({ type: Array, attribute: "score-items" })
scoreItems: ScoreItem[] = [];

Check warning on line 42 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L42

Added line #L42 was not covered by tests
@property({ type: Boolean, attribute: "total-visible" })
totalVisible: boolean = false;

Check warning on line 44 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L44

Added line #L44 was not covered by tests

tableRef: Ref<HTMLDivElement> = createRef();

Check warning on line 46 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L46

Added line #L46 was not covered by tests
table: JspreadsheetInstance;

@property({ state: true })
hasErrors: boolean = false;

Check warning on line 50 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L50

Added line #L50 was not covered by tests
@property({ state: true })
_totalVisible: boolean = false;

Check warning on line 52 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L52

Added line #L52 was not covered by tests

watch = {
totalVisible: () => {
this._totalVisible = this.totalVisible;

Check warning on line 56 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L54-L56

Added lines #L54 - L56 were not covered by tests
}
};

toggleTotalVisible(): void {
this._totalVisible = !this._totalVisible;

Check warning on line 61 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L60-L61

Added lines #L60 - L61 were not covered by tests
}

get tableWidth(): number {
return this.tableRef.value.clientWidth;

Check warning on line 65 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L64-L65

Added lines #L64 - L65 were not covered by tests
}

get descriptionColWidth(): number {

Check warning on line 68 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L68

Added line #L68 was not covered by tests
if (!this.tableRef.value) {
return 200;

Check warning on line 70 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L70

Added line #L70 was not covered by tests
}

// full width - borders - name column - maximum column - visible column - index column - delete column
const variableWidth = this.tableWidth - 14 - 200 - 75 - 75 - 50 - 30;
return Math.max(200, variableWidth);

Check warning on line 75 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L74-L75

Added lines #L74 - L75 were not covered by tests
}

get data(): CellData[][] {
return [
...this.scoreItems.map(item => [

Check warning on line 80 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L78-L80

Added lines #L78 - L80 were not covered by tests
item.id,
item.name,
item.description,
item.maximum,
item.visible
]),
["", "", "", "", false]
];
}

get editedScoreItems(): ScoreItem[] {
const tableData = this.table.getData();

Check warning on line 92 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L91-L92

Added lines #L91 - L92 were not covered by tests

const scoreItems = tableData.map((row: CellData[], index: number) => {
return {

Check warning on line 95 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L94-L95

Added lines #L94 - L95 were not covered by tests
id: row[0] as number | null,
name: row[1] as string,
description: row[2] as string,
maximum: (row[3] as string).replace(",", "."), // replace comma with dot for float representation
visible: toBoolean(row[4]),
order: index,
};
});

// filter out empty rows
return scoreItems.filter(item => !(item.name === "" && item.maximum === "" && item.description === "" && item.visible === false));
}

deleteCellRow(cell: HTMLTableCellElement): void {
const row = cell.parentElement as HTMLTableRowElement;
this.table.deleteRow(row.rowIndex-1);

Check warning on line 111 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L109-L111

Added lines #L109 - L111 were not covered by tests
}

createDeleteButton(cell: HTMLTableCellElement): HTMLTableCellElement {
const button = html`<button

Check warning on line 115 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L114-L115

Added lines #L114 - L115 were not covered by tests
class="btn btn-icon d-btn-danger btn-icon-inline"
title="${i18n.t("js.score_items.jspreadsheet.deleteRow")}"
@click="${() => this.deleteCellRow(cell)}">

Check warning on line 118 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L118

Added line #L118 was not covered by tests
<i class="mdi mdi-18 mdi-delete"></i>
</button>`;
render(button, cell);
return cell;

Check warning on line 122 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L121-L122

Added lines #L121 - L122 were not covered by tests
}

customCheckboxEditor(): CustomEditor {
const updateCell = (cell: HTMLTableCellElement): void => {
this.table.setValue(cell, !toBoolean(this.table.getValue(cell)));

Check warning on line 127 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L125-L127

Added lines #L125 - L127 were not covered by tests
};
return {
createCell: (cell: HTMLTableCellElement) => {
const current = cell.innerHTML === "true";
const checkbox = html`<div class="form-check" contenteditable="false" style="white-space: normal;">

Check warning on line 132 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L129-L132

Added lines #L129 - L132 were not covered by tests
<input type="checkbox"
class="form-check-input"
?checked="${current}"
@change="${() => updateCell(cell)}">

Check warning on line 136 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L136

Added line #L136 was not covered by tests
</div>`;
cell.innerHTML = "";
render(checkbox, cell);
return cell;

Check warning on line 140 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L138-L140

Added lines #L138 - L140 were not covered by tests
},
openEditor: () => false,
closeEditor: (cell: HTMLTableCellElement) => {
return toBoolean(this.table.getValue(cell));

Check warning on line 144 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L142-L144

Added lines #L142 - L144 were not covered by tests
},
updateCell: (cell: HTMLTableCellElement, value: CellValue) => {
const checkbox = cell.querySelector("input");

Check warning on line 147 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L146-L147

Added lines #L146 - L147 were not covered by tests
if (checkbox) {
checkbox.checked = toBoolean(value);

Check warning on line 149 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L149

Added line #L149 was not covered by tests
}
return toBoolean(value);

Check warning on line 151 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L151

Added line #L151 was not covered by tests
}
};
}

get columnConfig(): ColumnWithTooltip[] {
return [

Check warning on line 157 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L156-L157

Added lines #L156 - L157 were not covered by tests
{ type: "hidden", title: "id" },
{ type: "text", title: i18n.t("js.score_items.name"), width: 200, align: "left" },
{ type: "text", title: i18n.t("js.score_items.description"), width: this.descriptionColWidth, align: "left", tooltip: i18n.t("js.score_items.description_help") },
{ type: "numeric", title: i18n.t("js.score_items.maximum"), width: 75, align: "left", tooltip: i18n.t("js.score_items.maximum_help") },
{ type: "html", title: i18n.t("js.score_items.visible"), width: 75, align: "left", tooltip: i18n.t("js.score_items.visible_help"), editor: this.customCheckboxEditor() },
{ type: "html", title: " ", width: 30, align: "center", readOnly: true, editor: {
createCell: (cell: HTMLTableCellElement) => this.createDeleteButton(cell),

Check warning on line 164 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L164

Added line #L164 was not covered by tests
} },
];
}

async initTable(): Promise<void> {

Check warning on line 169 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L169

Added line #L169 was not covered by tests
// Wait for translations to be present
await ready;

Check warning on line 171 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L171

Added line #L171 was not covered by tests

this.table = jspreadsheet(this.tableRef.value, {

Check warning on line 173 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L173

Added line #L173 was not covered by tests
root: this,
data: this.data,
columns: this.columnConfig,
text: {
copy: i18n.t("js.score_items.jspreadsheet.copy"),
deleteSelectedRows: i18n.t("js.score_items.jspreadsheet.deleteSelectedRows"),
insertANewRowAfter: i18n.t("js.score_items.jspreadsheet.insertNewRowAfter"),
insertANewRowBefore: i18n.t("js.score_items.jspreadsheet.insertNewRowBefore"),
paste: i18n.t("js.score_items.jspreadsheet.paste"),
},
about: false,
allowDeleteColumn: false,
allowDeleteRow: true,
allowInsertColumn: false,
allowInsertRow: true,
allowManualInsertColumn: false,
allowManualInsertRow: true,
allowRenameColumn: false,
columnResize: false,
columnSorting: false,
minSpareRows: 1,
parseFormulas: false,
selectionCopy: false,
wordWrap: true,
defaultRowHeight: 30,
allowExport: false,
});
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved

// init tooltips
this.columnConfig.forEach((column, index) => {
const td = this.tableRef.value.querySelector(`thead td[data-x="${index}"]`);

Check warning on line 204 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L203-L204

Added lines #L203 - L204 were not covered by tests
if (td && column.tooltip) {
td.setAttribute("title", column.tooltip);
new Tooltip(td);

Check warning on line 207 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L206-L207

Added lines #L206 - L207 were not covered by tests
}
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
});

// mark header and menu as non-editable
this.tableRef.value.querySelector("thead").setAttribute("contenteditable", "false");
this.tableRef.value.querySelector(".jexcel_contextmenu").setAttribute("contenteditable", "false");

Check warning on line 213 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L212-L213

Added lines #L212 - L213 were not covered by tests


// update description column width when the window is resized
new ResizeObserver(() => {
this.table.setWidth(2, this.descriptionColWidth);

Check warning on line 218 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L217-L218

Added lines #L217 - L218 were not covered by tests
}).observe(this.tableRef.value);
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
}

protected firstUpdated(_changedProperties: PropertyValues): void {
super.firstUpdated(_changedProperties);

Check warning on line 223 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L222-L223

Added lines #L222 - L223 were not covered by tests

this.initTable();

Check warning on line 225 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L225

Added line #L225 was not covered by tests
}

validate(): boolean {

Check warning on line 228 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L228

Added line #L228 was not covered by tests
// Remove all error classes
this.tableRef.value.querySelectorAll("td.error").forEach(cell => {
cell.classList.remove("error");

Check warning on line 231 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L230-L231

Added lines #L230 - L231 were not covered by tests
});

const invalidCells: string[] = [];
const data = this.editedScoreItems;
data.forEach(item => {
const row = item.order + 1;

Check warning on line 237 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L234-L237

Added lines #L234 - L237 were not covered by tests
if (item.name === "") {
invalidCells.push("B" + row);

Check warning on line 239 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L239

Added line #L239 was not covered by tests
}
// Check if maximum is a positive number < 1000
// we use a regex instead of parseFloat because parseFloat is too lenient
if (!/^\d{1,3}(\.\d+)?$/.test(item.maximum) || parseFloat(item.maximum) <= 0) {
invalidCells.push("D" + row);

Check warning on line 244 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L244

Added line #L244 was not covered by tests
}
});
invalidCells.forEach(cell => {
this.table.getCell(cell).classList.add("error");

Check warning on line 248 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L247-L248

Added lines #L247 - L248 were not covered by tests
});
this.hasErrors = invalidCells.length > 0;
return !this.hasErrors;

Check warning on line 251 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L250-L251

Added lines #L250 - L251 were not covered by tests
}

confirmWarnings(): boolean {
const old = this.scoreItems;
const edited = this.editedScoreItems;
const removed = old.some(item => !edited.some(e => e.id === item.id));

Check warning on line 257 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L254-L257

Added lines #L254 - L257 were not covered by tests
const maxEdited = old.some(item => edited.some(e => e.id === item.id && e.maximum !== item.maximum));

let warnings = "";

Check warning on line 260 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L260

Added line #L260 was not covered by tests
if (removed) {
warnings += i18n.t("js.score_items.deleted_warning") + "\n";

Check warning on line 262 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L262

Added line #L262 was not covered by tests
}
if (maxEdited) {
warnings += i18n.t("js.score_items.modified_warning") + "\n";

Check warning on line 265 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L265

Added line #L265 was not covered by tests
}

return warnings === "" || confirm(warnings);
}

async save(): Promise<void> {

Check warning on line 271 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L271

Added line #L271 was not covered by tests
if (!this.validate()) {
return;

Check warning on line 273 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L273

Added line #L273 was not covered by tests
}

if (!this.confirmWarnings()) {
return;

Check warning on line 277 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L277

Added line #L277 was not covered by tests
}

const response = await fetch(this.route, {

Check warning on line 280 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L280

Added line #L280 was not covered by tests
method: "PATCH",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
evaluation_exercise: {
visible_score: this._totalVisible,
score_items: this.editedScoreItems
}
})
});
if (response.ok) {
const js = await response.text();
eval(js);

Check warning on line 294 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L293-L294

Added lines #L293 - L294 were not covered by tests
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
}
}

cancel(): void {

Check warning on line 298 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L298

Added line #L298 was not covered by tests
if (this.table) {
this.table.setData(this.data);
this._totalVisible = this.totalVisible;
this.hasErrors = false;

Check warning on line 302 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L300-L302

Added lines #L300 - L302 were not covered by tests
}
this.dispatchEvent(new Event("cancel"));

Check warning on line 304 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L304

Added line #L304 was not covered by tests
}


render(): TemplateResult {
return html`

Check warning on line 309 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L308-L309

Added lines #L308 - L309 were not covered by tests
${this.hasErrors ? html`
<div class="alert alert-danger">${i18n.t("js.score_items.validation_warning")}</div>` : ""}

Check warning on line 311 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L311

Added line #L311 was not covered by tests
<div style="width: 100%" ${ref(this.tableRef)} contenteditable="true"></div>
<div class="form-check ms-1">
<label class="form-check-label" for="total-visible">
${i18n.t("js.score_items.total_visible")}
</label>
<input type="checkbox"
class="form-check-input"
id="total-visible"
?checked=${this._totalVisible}
@change=${() => this.toggleTotalVisible()}>

Check warning on line 321 in app/assets/javascripts/components/input_table.ts

View check run for this annotation

Codecov / codecov/patch

app/assets/javascripts/components/input_table.ts#L321

Added line #L321 was not covered by tests
</div>
<div class="d-flex justify-content-end">
<button @click=${this.cancel} class="btn btn-text me-1">
${i18n.t("js.score_items.cancel")}
</button>
<button @click=${this.save} class="btn btn-filled">
${i18n.t("js.score_items.save")}
</button>
</div>
`;
}
}
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
46 changes: 46 additions & 0 deletions app/assets/javascripts/i18n/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,29 @@
"score_item": {
"error": "Error while updating"
},
"score_items": {
"cancel": "Cancel",
"deleted_warning": "You have deleted one or more score items. This will also delete all scores for these items.",
"description": "Description",
"description_help": "A description is optional. Markdown formatting can be used. This is visible to the students.",
"jspreadsheet": {
"copy": "Copy...",
"deleteRow": "Delete row",
"deleteSelectedRows": "Delete selected rows",
"insertNewRowAfter": "Insert new row after",
"insertNewRowBefore": "Insert new row before",
"paste": "Paste..."
},
"maximum": "Maximum",
"maximum_help": "The maximum grade for this score item. The grade should be between 0 and 1000, and works in increments of 0.25.",
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
"modified_warning": "You have changed the maximum score of one or more score items. This will mark all completed evaluations with this score item as uncompleted.",
"name": "Name",
"save": "Save",
"total_visible": "Make the total score visible to students once the evaluation is released.",
"validation_warning": "All score items must have a name and a maximum score, and the maximum score must be between 0 and 1000.",
"visible": "Visible",
"visible_help": "Make the score item visible to students once the evaluation is released."
},
"search": {
"filter": {
"course_id": "Course",
Expand Down Expand Up @@ -825,6 +848,29 @@
"score_item": {
"error": "Fout bij bijwerken"
},
"score_items": {
"cancel": "Annuleren",
"deleted_warning": "Je hebt een of meerdere scoreonderdelen verwijderd. Dit zal ook de bijhorende scores van de studenten verwijderen.",
"description": "Beschrijving",
"description_help": "Een beschrijving is optioneel en kan in Markdown geschreven worden. Dit is zichtbaar voor de studenten.",
"jspreadsheet": {
"copy": "Kopieer...",
"deleteRow": "Verwijder rij",
"deleteSelectedRows": "Verwijder geselecteerde rijen",
"insertNewRowAfter": "Voeg nieuwe rij toe na deze",
"insertNewRowBefore": "Voeg nieuwe rij toe voor deze",
"paste": "Plak..."
},
"maximum": "Maximum",
"maximum_help": "De maximumscore voor dit scoreonderdeel. Dit moet een getal zijn tussen 0 en 1000 en gaat in stappen van 0.25.",
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
"modified_warning": "Je hebt de maximumscore van een of meerdere scoreonderdelen aangepast. Alle afgewerkte evaluaties met dit scoreonderdeel zullen terug als onafgewerkt gemarkeerd worden.",
"name": "Naam",
"save": "Opslaan",
"total_visible": "Maak totaal score zichtbaar voor studenten eens de evaluatie vrijgegeven is.",
"validation_warning": "Alle scoreonderdelen moeten een naam en een maximumscore hebben. De maximumscore moet een getal zijn tussen 0 en 1000.",
"visible": "Zichtbaar",
"visible_help": "Maak het scoreonderdeel zichtbaar voor studenten eens de evaluatie vrijgegeven is."
},
"search": {
"filter": {
"course_id": "Cursus",
Expand Down
Loading
Loading