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

Allow responding to annotations in a thread #4404

Merged
merged 112 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
0f4eaec
Allow responding to conversations
jorg-vr Feb 10, 2023
65fe9b5
Add tests
jorg-vr Feb 10, 2023
ec76b21
Auto answer questions in thread
jorg-vr Feb 10, 2023
19ee002
Allow thread_root_id in policy
jorg-vr Feb 13, 2023
db144b3
Use more subdirectories
jorg-vr Feb 13, 2023
2009cf8
Add slots to shadowless ellements
jorg-vr Feb 14, 2023
1d8afd8
Revert "Add slots to shadowless ellements"
jorg-vr Feb 14, 2023
65097f9
Use campire plugin to support slots
jorg-vr Feb 14, 2023
d8ea113
Fix docs
jorg-vr Feb 14, 2023
8988ceb
Create new structure
jorg-vr Feb 14, 2023
93722e1
Create machine annotation
jorg-vr Feb 14, 2023
88279af
Start of annotation user
jorg-vr Feb 15, 2023
1ad68a6
Use abstraction instead of template
jorg-vr Feb 15, 2023
7be03fc
Implement question annotation
jorg-vr Feb 15, 2023
8325144
Remove a layer of abstraction
jorg-vr Feb 16, 2023
997bb84
Remove a layer of abstraction
jorg-vr Feb 16, 2023
7ae410a
Create state to manage state
jorg-vr Feb 16, 2023
3417056
Create codelisting row
jorg-vr Feb 16, 2023
1a80766
Undo removal of highlighting
jorg-vr Feb 16, 2023
59c0f82
Use state for annotation visibility
jorg-vr Feb 17, 2023
7562d70
Add invisble nnotice dot
jorg-vr Feb 17, 2023
3f1b30b
Add invisble notice dot
jorg-vr Feb 17, 2023
ceeafaa
Insert webcomponents in table
jorg-vr Feb 22, 2023
91a3bcf
Allow creating new annotations
jorg-vr Feb 22, 2023
872f5af
Fix annotation colors
jorg-vr Feb 23, 2023
a12bbee
Move question mode to state
jorg-vr Feb 23, 2023
1447014
Reintroduce remove annotation button
jorg-vr Feb 23, 2023
c61b600
Fix bug
jorg-vr Feb 23, 2023
c58714c
Remove extra whitespace in machine annotations
jorg-vr Feb 23, 2023
3a356d2
Fix edditing
jorg-vr Feb 23, 2023
50e2b75
Recreate hide buttons
jorg-vr Feb 23, 2023
427a0a6
Fix global annotations
jorg-vr Feb 24, 2023
54227ba
Reintroduce annotation count badge
jorg-vr Feb 24, 2023
190823a
remove comment
jorg-vr Feb 24, 2023
c9564ca
only fetch user annotations when required
jorg-vr Feb 27, 2023
9aaa380
Fix i18n
jorg-vr Feb 27, 2023
9be849b
Only show add annotation buttons when allowed
jorg-vr Feb 27, 2023
c6c0924
Get rid of state in codelisting class
jorg-vr Feb 27, 2023
b7af102
Make codelisting an object instead of a class
jorg-vr Feb 27, 2023
caf4aca
Show errors on annotaion form
jorg-vr Feb 28, 2023
36b5907
Fix linting
jorg-vr Feb 28, 2023
da15b12
Add threads
jorg-vr Feb 28, 2023
6c05ed7
Improve layout
jorg-vr Feb 28, 2023
bfd9b57
Improve layout
jorg-vr Feb 28, 2023
02a73d7
Fix released icon
jorg-vr Feb 28, 2023
767bffd
Always show thread
jorg-vr Feb 28, 2023
7cc75e1
Replace edit button by dropdown
jorg-vr Feb 28, 2023
63ccb2b
Reintroduce highlighting
jorg-vr Mar 2, 2023
3d90350
Fix annotation form buttons
jorg-vr Mar 2, 2023
bdb024b
fix save annotation button
jorg-vr Mar 2, 2023
becfd88
Redesign thread layout
jorg-vr Mar 2, 2023
de1c78f
Add mark as answered
jorg-vr Mar 2, 2023
8403afd
Reintroduce question states
jorg-vr Mar 3, 2023
aadb974
Don't allow deleting the root of an active thread
jorg-vr Mar 3, 2023
cdb0d74
Reset in progress to unanswered after one hour
jorg-vr Mar 3, 2023
7086047
Remove unused vampire slot system
jorg-vr Mar 3, 2023
da12a39
Merge branch 'develop' into feature/question-threading
jorg-vr Mar 3, 2023
10bdaf2
Reintroduce comments in shadowless lit element
jorg-vr Mar 3, 2023
a6b6941
Remove unused files
jorg-vr Mar 3, 2023
bd76932
Fix tests
jorg-vr Mar 3, 2023
916147a
Remove unsed commented code
jorg-vr Mar 3, 2023
f326098
remove unused import
jorg-vr Mar 3, 2023
d6fa6ad
Fix rails tests
jorg-vr Mar 3, 2023
70d2423
Fix system tests
jorg-vr Mar 6, 2023
eaff9b1
Fix typescript
jorg-vr Mar 6, 2023
aec9c11
Do not make codelisting an explicit object in the module
jorg-vr Mar 6, 2023
eab7385
Add documentation to the new components
jorg-vr Mar 6, 2023
82c1c8c
Fix test
jorg-vr Mar 6, 2023
3995067
Fix dropdown overflow
jorg-vr Mar 6, 2023
42b7146
Refresh thread after annotation delete or add
jorg-vr Mar 6, 2023
239e9ad
Fix user annotaion count for threads
jorg-vr Mar 6, 2023
2ee9315
Rename meta to header
jorg-vr Mar 6, 2023
ea5386e
Simplify saved annotation related code
jorg-vr Mar 6, 2023
e286c2a
Remove saved annoptation tracking responsibility from user annotation
jorg-vr Mar 6, 2023
b4bd7c6
Don't use relative paths to javascript
jorg-vr Mar 6, 2023
25bb6f1
Remove unreqiered import
jorg-vr Mar 6, 2023
57bf42b
Name function more logically
jorg-vr Mar 6, 2023
f633928
FIx modal tests
jorg-vr Mar 7, 2023
99669d9
Merge branch 'develop' into feature/question-threading
jorg-vr Mar 7, 2023
7221137
Add tests for questions
jorg-vr Mar 7, 2023
e01cc91
Add annotation tests
jorg-vr Mar 7, 2023
beceef5
Fix linting
jorg-vr Mar 7, 2023
c37a14a
Fix tests
jorg-vr Mar 7, 2023
8d15a7e
Reset javascript version
jorg-vr Mar 14, 2023
e4e0895
Fix save annotation icon size
jorg-vr Mar 14, 2023
8b3c9a9
Fix tooltips for show annotation toggles
jorg-vr Mar 14, 2023
a6bb459
Merge branch 'develop' into feature/question-threading
jorg-vr Mar 14, 2023
049c4b7
Fix untranslated string
jorg-vr Mar 15, 2023
6e04072
Move new saved annotation option to top
jorg-vr Mar 15, 2023
1fce3c3
Update notation
jorg-vr Mar 15, 2023
47ef509
Better test delayed job effect
jorg-vr Mar 15, 2023
8c974ae
Merge branch 'develop' into feature/question-threading
jorg-vr Mar 15, 2023
b8838c0
Add extra test on question state
jorg-vr Mar 15, 2023
3d456f6
Merge branch 'develop' into feature/question-threading
jorg-vr Mar 21, 2023
896d452
Improve help text for questions
jorg-vr Mar 23, 2023
254a711
Merge branch 'develop' into feature/question-threading
jorg-vr Mar 23, 2023
4b0dfe4
Add option to transition emails to unanswered
jorg-vr Mar 23, 2023
95927b2
Visuallise if a question has been marked as answered
jorg-vr Mar 23, 2023
61458fd
Better permission checks for actions
jorg-vr Mar 27, 2023
8157e65
Fix option permissions
jorg-vr Mar 27, 2023
b1efddf
Update all previous questions
jorg-vr Mar 27, 2023
72dd9be
Replace beantwoorden by antwoorden
jorg-vr Mar 27, 2023
acefb9c
Merge branch 'feature/question-threading' of github.com:dodona-edu/do…
jorg-vr Mar 27, 2023
3d0455f
Fix tests
jorg-vr Mar 27, 2023
0ccb402
Merge branch 'develop' into feature/question-threading
jorg-vr Mar 27, 2023
fed76d0
Modernize tests
jorg-vr Mar 28, 2023
d51c5be
Merge branch 'develop' into feature/question-threading
jorg-vr Mar 29, 2023
b73e96f
Translate reply as reageer
jorg-vr Mar 29, 2023
709f859
Modal mixin is not meta
jorg-vr Mar 29, 2023
33d9bb1
Rename questionMode to isQuestionMode
jorg-vr Mar 29, 2023
ecc4fe4
Update app/assets/javascripts/state/UserAnnotations.ts
jorg-vr Apr 11, 2023
54508b0
Merge branch 'develop' into feature/question-threading
jorg-vr Apr 11, 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
16 changes: 8 additions & 8 deletions app/assets/javascripts/components/annotations/annotation_form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "components/saved_annotations/saved_annotation_input";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { getCourseId } from "state/Courses";
import { stateMixin } from "state/StateMixin";
import { getQuestionMode } from "state/Annotations";
import { isQuestionMode } from "state/Annotations";

// Min and max of the annotation text is defined in the annotation model.
const maxLength = 10_000;
Expand Down Expand Up @@ -68,12 +68,12 @@ export class AnnotationForm extends stateMixin(watchMixin(ShadowlessLitElement))
return getCourseId();
}

get questionMode(): boolean {
return getQuestionMode();
get isQuestionMode(): boolean {
return isQuestionMode();
}

get type(): string {
return this.questionMode ? "user_question" : "user_annotation";
return this.isQuestionMode ? "user_question" : "user_annotation";
}

get rows(): number {
Expand Down Expand Up @@ -154,7 +154,7 @@ export class AnnotationForm extends stateMixin(watchMixin(ShadowlessLitElement))
render(): TemplateResult {
return html`
<form class="annotation-submission form">
${this.questionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse(this.courseId) ? "" : html`
${this.isQuestionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse(this.courseId) ? "" : html`
<d-saved-annotation-input
name="saved_annotation_id"
class="saved-annotation-input"
Expand All @@ -164,7 +164,7 @@ export class AnnotationForm extends stateMixin(watchMixin(ShadowlessLitElement))
></d-saved-annotation-input>
`}
<div class="field form-group">
${this.questionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse(this.courseId) ? "" : html`
${this.isQuestionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse(this.courseId) ? "" : html`
<label class="form-label" for="annotation-text">
${I18n.t("js.user_annotation.fields.annotation_text")}
</label>
Expand All @@ -183,15 +183,15 @@ export class AnnotationForm extends stateMixin(watchMixin(ShadowlessLitElement))
></textarea>
<div class="clearfix annotation-help-block">
<span class='help-block'>${unsafeHTML(I18n.t("js.user_annotation.help"))}</span>
${this.questionMode ? html`
${this.isQuestionMode ? html`
<span class='help-block'>${unsafeHTML(I18n.t("js.user_annotation.help_student"))}</span>
` : ""}
<span class="help-block float-end">
<span class="used-characters">${I18n.formatNumber(this._annotationText.length)}</span> / ${I18n.formatNumber(maxLength)}
</span>
</div>
</div>
${this.questionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse(this.courseId) ? "" : html`
${this.isQuestionMode || /* REMOVE AFTER CLOSED BETA */ !isBetaCourse(this.courseId) ? "" : html`
<div class="field form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" @click="${() => this.toggleSaveAnnotation()}" id="check-save-annotation">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { customElement, property } from "lit/decorators.js";
import { ShadowlessLitElement } from "components/meta/shadowless_lit_element";
import { html, TemplateResult } from "lit";
import { stateMixin } from "state/StateMixin";
import { getQuestionMode } from "state/Annotations";
import { isQuestionMode } from "state/Annotations";
import "components/annotations/annotations_toggles";
import "components/annotations/hidden_annotations_dot";
import { i18nMixin } from "components/meta/i18n_mixin";
Expand All @@ -22,16 +22,16 @@ export class AnnotationOptions extends i18nMixin(stateMixin(ShadowlessLitElement

state = ["getQuestionMode", "hasPermission"];

get questionMode(): boolean {
return getQuestionMode();
get isQuestionMode(): boolean {
return isQuestionMode();
}

get canCreateAnnotation(): boolean {
return hasPermission("annotation.create");
}

get addAnnotationTitle(): string {
return this.questionMode ?
return this.isQuestionMode ?
I18n.t("js.annotations.options.add_global_question") :
I18n.t("js.annotations.options.add_global_annotation");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
UserAnnotationFormData
} from "state/UserAnnotations";
import { getEvaluationId } from "state/Evaluations";
import { getQuestionMode, isAnnotationVisible } from "state/Annotations";
import { isQuestionMode, isAnnotationVisible } from "state/Annotations";
import { getSubmissionId } from "state/Submissions";
import { getMachineAnnotationsByLine, MachineAnnotationData } from "state/MachineAnnotations";
import "components/annotations/machine_annotation";
Expand Down Expand Up @@ -49,8 +49,8 @@ export class AnnotationsCell extends stateMixin(ShadowlessLitElement) {
return getUserAnnotationsByLine(this.row);
}

get questionMode(): boolean {
return getQuestionMode();
get isQuestionMode(): boolean {
return isQuestionMode();
}


Expand All @@ -63,7 +63,7 @@ export class AnnotationsCell extends stateMixin(ShadowlessLitElement) {
};

try {
const mode = getQuestionMode() ? "question" : "annotation";
const mode = isQuestionMode() ? "question" : "annotation";
await createUserAnnotation(annotationData, getSubmissionId(), mode, e.detail.saveAnnotation, e.detail.savedAnnotationTitle);
this.closeForm();
} catch (err) {
Expand All @@ -89,7 +89,7 @@ export class AnnotationsCell extends stateMixin(ShadowlessLitElement) {
return html`
<div class="annotation-cell">
${this.showForm ? html`
<div class="annotation ${this.questionMode ? "question" : "user" }">
<div class="annotation ${this.isQuestionMode ? "question" : "user" }">
<d-annotation-form @submit=${e => this.createAnnotation(e)}
@cancel=${() => this.closeForm()}
${ref(this.annotationFormRef)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { unsafeHTML } from "lit/directives/unsafe-html.js";
import "components/annotations/hidden_annotations_dot";
import "components/annotations/annotations_cell";
import { i18nMixin } from "components/meta/i18n_mixin";
import { getQuestionMode } from "state/Annotations";
import { isQuestionMode } from "state/Annotations";
import { stateMixin } from "state/StateMixin";
import { initTooltips } from "util.js";
import { PropertyValues } from "@lit/reactive-element";
Expand Down Expand Up @@ -38,16 +38,16 @@ export class CodeListingRow extends stateMixin(i18nMixin(ShadowlessLitElement))
initTooltips(this);
}

get questionMode(): boolean {
return getQuestionMode();
get isQuestionMode(): boolean {
return isQuestionMode();
}

get canCreateAnnotation(): boolean {
return hasPermission("annotation.create");
}

get addAnnotationTitle(): string {
return this.questionMode ? I18n.t("js.annotations.options.add_question") : I18n.t("js.annotations.options.add_annotation");
return this.isQuestionMode ? I18n.t("js.annotations.options.add_question") : I18n.t("js.annotations.options.add_annotation");
}

render(): TemplateResult {
Expand Down
33 changes: 13 additions & 20 deletions app/assets/javascripts/components/annotations/thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { ShadowlessLitElement } from "components/meta/shadowless_lit_element";
import { customElement, property } from "lit/decorators.js";
import {
createUserAnnotation, invalidateUserAnnotation,
transition,
transition, transitionAll,
UserAnnotationData,
UserAnnotationFormData
} from "state/UserAnnotations";
import { html, TemplateResult } from "lit";
import { getEvaluationId } from "state/Evaluations";
import { getQuestionMode } from "state/Annotations";
import { isQuestionMode } from "state/Annotations";
import { getSubmissionId } from "state/Submissions";
import { AnnotationForm } from "components/annotations/annotation_form";
import { createRef, Ref, ref } from "lit/directives/ref.js";
Expand All @@ -35,18 +35,17 @@ export class Thread extends i18nMixin(stateMixin(ShadowlessLitElement)) {

state = ["getUserAnnotations", "getQuestionMode"];

get questionMode(): boolean {
return getQuestionMode();
get isQuestionMode(): boolean {
return isQuestionMode();
}

get openQuestion(): UserAnnotationData | undefined {
return this.data.question_state !== undefined && this.data.question_state !== "answered" ?
this.data :
this.data.responses.find(response => response.question_state !== undefined && response.question_state !== "answered");
get openQuestions(): UserAnnotationData[] | undefined {
return [this.data, ...this.data.responses]
.filter(response => response.question_state !== undefined && response.question_state !== "answered");
}

get isUnanswered(): boolean {
return this.openQuestion != undefined;
return this.openQuestions.length > 0;
}

async createAnnotation(e: CustomEvent): Promise<void> {
Expand All @@ -59,7 +58,7 @@ export class Thread extends i18nMixin(stateMixin(ShadowlessLitElement)) {
};

try {
const mode = getQuestionMode() ? "question" : "annotation";
const mode = isQuestionMode() ? "question" : "annotation";
await createUserAnnotation(annotationData, getSubmissionId(), mode, e.detail.saveAnnotation, e.detail.savedAnnotationTitle);

invalidateUserAnnotation(this.data.id);
Expand All @@ -71,21 +70,15 @@ export class Thread extends i18nMixin(stateMixin(ShadowlessLitElement)) {
}

markAsResolved(): void {
if (this.openQuestion !== undefined) {
transition(this.openQuestion, "answered");
}
transitionAll(this.openQuestions, "answered");
}

markAsInProgress(): void {
if (this.openQuestion?.question_state !== "in_progress") {
transition(this.openQuestion, "in_progress");
}
transitionAll(this.openQuestions.filter(question => question.question_state !== "in_progress"), "in_progress");
}

markAsUnanswered(): void {
if (this.openQuestion?.question_state !== "unanswered") {
transition(this.openQuestion, "unanswered");
}
transitionAll(this.openQuestions.filter(question => question.question_state !== "unanswered"), "unanswered");
}

addReply(): void {
Expand All @@ -107,7 +100,7 @@ export class Thread extends i18nMixin(stateMixin(ShadowlessLitElement)) {
<d-user-annotation .data=${response}></d-user-annotation>
`)}
${this.showForm ? html`
<div class="annotation ${this.questionMode ? "question" : "user" }">
<div class="annotation ${this.isQuestionMode ? "question" : "user" }">
<d-annotation-form @submit=${e => this.createAnnotation(e)}
${ref(this.annotationFormRef)}
@cancel=${() => this.cancelReply()}
Expand Down
80 changes: 59 additions & 21 deletions app/assets/javascripts/components/annotations/user_annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { html, PropertyValues, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { ShadowlessLitElement } from "components/meta/shadowless_lit_element";
import { deleteUserAnnotation, updateUserAnnotation, UserAnnotationData } from "state/UserAnnotations";
import { deleteUserAnnotation, updateUserAnnotation, UserAnnotationData, transition } from "state/UserAnnotations";
import { i18nMixin } from "components/meta/i18n_mixin";
import { AnnotationForm } from "components/annotations/annotation_form";
import { createRef, Ref, ref } from "lit/directives/ref.js";
import "components/saved_annotations/new_saved_annotation";
import { getQuestionMode } from "state/Annotations";
import { isQuestionMode } from "state/Annotations";
import { initTooltips } from "util.js";
import "components/saved_annotations/saved_annotation_icon";

Expand Down Expand Up @@ -42,7 +42,7 @@ export class UserAnnotation extends i18nMixin(ShadowlessLitElement) {
}

get type(): string {
return getQuestionMode() ? "user_question" : "user_annotation";
return isQuestionMode() ? "user_question" : "user_annotation";
}

protected get header(): TemplateResult {
Expand Down Expand Up @@ -83,6 +83,13 @@ export class UserAnnotation extends i18nMixin(ShadowlessLitElement) {
data-bs-placement="top"
></i>
` : ""}
${ this.data.question_state == "answered" ? html`
<i class="mdi mdi-comment-check-outline mdi-18 annotation-meta-icon"
title="${I18n.t("js.user_question.is_answered")}"
data-bs-toggle="tooltip"
data-bs-placement="top"
></i>
` : ""}
`;
}

Expand Down Expand Up @@ -114,36 +121,67 @@ export class UserAnnotation extends i18nMixin(ShadowlessLitElement) {
initTooltips(this);
}

reopenQuestion(): void {
transition(this.data, "unanswered");
}

get dropdownOptions(): TemplateResult[] {
const options = [];

if (this.data.permission.update) {
options.push(html`
<li>
<a class="dropdown-item" @click="${() => this.editing = true}">
<i class="mdi mdi-pencil mdi-18"></i> ${I18n.t(`js.${this.type}.edit`)}
</a>
</li>
`);
}
if (this.data.permission.save) {
options.push(html`
<d-new-saved-annotation
from-annotation-id="${this.data.id}"
annotation-text="${this.data.annotation_text}"
.savedAnnotationId="${this.data.saved_annotation_id}">
</d-new-saved-annotation>
`);
}
if (this.data.permission.destroy) {
options.push(html`
<li>
<a class="dropdown-item" @click="${() => this.deleteAnnotation()}">
<i class="mdi mdi-delete mdi-18"></i> ${I18n.t(`js.user_annotation.delete`)}
</a>
</li>
`);
}
if (this.data.permission.transition?.unanswered) {
options.push(html`
<li>
<a class="dropdown-item" @click="${() => this.reopenQuestion()}">
<i class="mdi mdi-comment-question-outline mdi-18"></i> ${I18n.t("js.user_question.unresolve")}
</a>
</li>
`);
}

return options;
}

render(): TemplateResult {
return html`
<div class="annotation ${this.data.type == "annotation" ? "user" : "question"}">
<div class="annotation-header">
<span class="annotation-meta">
${this.header}
</span>
${this.data.permission.update ? html`
${this.dropdownOptions.length > 0 ? html`
<div class="dropdown actions float-end" id="kebab-menu">
<a class="btn btn-icon btn-icon-inverted dropdown-toggle" data-bs-toggle="dropdown">
<i class="mdi mdi-dots-horizontal text-muted"></i>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<d-new-saved-annotation
from-annotation-id="${this.data.id}"
annotation-text="${this.data.annotation_text}"
.savedAnnotationId="${this.data.saved_annotation_id}">
</d-new-saved-annotation>
<li>
<a class="dropdown-item" @click="${() => this.editing = true}">
<i class="mdi mdi-pencil mdi-18"></i> ${I18n.t(`js.${this.type}.edit`)}
</a>
</li>
${ this.data.permission.destroy ? html`
<li>
<a class="dropdown-item" @click="${() => this.deleteAnnotation()}">
<i class="mdi mdi-delete mdi-18"></i> ${I18n.t(`js.user_annotation.delete`)}
</a>
</li>
` : ""}
${this.dropdownOptions}
</ul>
</div>
` : ""}
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/components/copy_button.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ShadowlessLitElement } from "components/shadowless_lit_element";
import { ShadowlessLitElement } from "components/meta/shadowless_lit_element";
import { html, PropertyValues, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import { initTooltips, ready } from "util.js";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { html, TemplateResult } from "lit";
import { ShadowlessLitElement } from "components/meta/shadowless_lit_element";
import { SavedAnnotation, updateSavedAnnotation, deleteSavedAnnotation } from "state/SavedAnnotations";
import "./saved_annotation_form";
import { modalMixin } from "components/meta/modal_mixin";
import { modalMixin } from "components/modal_mixin";

/**
* This component represents an edit button for a saved annotation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { html, TemplateResult } from "lit";
import { ShadowlessLitElement } from "components/meta/shadowless_lit_element";
import { createSavedAnnotation, getSavedAnnotation, SavedAnnotation } from "state/SavedAnnotations";
import "./saved_annotation_form";
import { modalMixin } from "components/meta/modal_mixin";
import { modalMixin } from "components/modal_mixin";
import { isBetaCourse } from "saved_annotation_beta";
import { getCourseId } from "state/Courses";
import { stateMixin } from "state/StateMixin";
Expand Down
2 changes: 2 additions & 0 deletions app/assets/javascripts/exercise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Toast } from "./toast";
import GLightbox from "glightbox";
import { IFrameMessageData } from "iframe-resizer";
import { getCode } from "state/Submissions";
import { render } from "lit";
import { CopyButton } from "components/copy_button";

function showLightbox(content): void {
const lightbox = new GLightbox(content);
Expand Down
Loading