Merge pull request #14380 from pateljannat/discussions-single-topic

This commit is contained in:
Suraj Shetty 2021-10-12 13:35:42 +05:30 committed by GitHub
commit 828d158e4d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 126 additions and 69 deletions

View file

@ -57,7 +57,23 @@ context('Discussions', () => {
cy.get('.discussion-on-page:visible .comment-field').should('have.value', '');
};
const single_thread_discussion = () => {
cy.visit('/test-single-thread');
cy.get('.discussions-sidebar').should('have.length', 0);
cy.get('.reply').should('have.length', 0);
cy.get('.discussion-on-page .comment-field')
.type('This comment is being made on a single thread discussion.')
.should('have.value', 'This comment is being made on a single thread discussion.');
cy.get('.discussion-on-page .submit-discussion').click();
cy.wait(3000);
cy.get('.discussion-on-page').children(".reply-card").eq(-1).children(".reply-text")
.should('have.text', 'This comment is being made on a single thread discussion.\n');
};
it('reply through modal', reply_through_modal);
it('reply through comment box', reply_through_comment_box);
it('cancel and clear comment box', cancel_and_clear_comment_box);
it('single thread discussion', single_thread_discussion);
});

View file

@ -1,32 +1,35 @@
<form class="discussion-form">
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<input type="text" autocomplete="off" class="input-with-feedback form-control topic-title" data-fieldtype="Data"
data-fieldname="feedback_comments" placeholder="{{ _('Type title') }}" spellcheck="false"></input>
</div>
{% if not single_thread %}
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<input type="text" autocomplete="off" class="input-with-feedback form-control topic-title"
data-fieldtype="Data" data-fieldname="feedback_comments" placeholder="{{ _('Type title') }}"
spellcheck="false"></input>
</div>
</div>
</div>
{% endif %}
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<textarea type="text" autocomplete="off" class="input-with-feedback form-control comment-field"
data-fieldtype="Text" data-fieldname="feedback_comments" placeholder="{{ _('Type here. Use markdown to format.') }}"
spellcheck="false"></textarea>
</div>
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<textarea type="text" autocomplete="off" class="input-with-feedback form-control comment-field"
data-fieldtype="Text" data-fieldname="feedback_comments"
placeholder="{{ _('Type here. Use markdown to format.') }}" spellcheck="false"></textarea>
</div>
</div>
</div>
<div class="comment-footer">
<div class="small flex-grow-1">
{{ _("Press Cmd+Enter to post your comment") }}
</div>
<a class="dark-links cancel-comment hide"> {{ _("Cancel") }} </a>
<div class="button is-default submit-discussion pull-right mb-1" data-doctype="{{ doctype | urlencode }}"
data-docname="{{ docname | urlencode }}">
{{ _("Post") }} </div>
<div class="comment-footer">
<div class="small flex-grow-1">
{{ _("Press Cmd+Enter to post your comment") }}
</div>
</form>
<a class="dark-links cancel-comment hide"> {{ _("Cancel") }} </a>
<div class="button is-default submit-discussion pull-right mb-1">
{{ _("Post") }}
</div>
</div>
</form>

View file

@ -87,29 +87,43 @@ const setup_socket_io = () => {
};
const publish_message = (data) => {
const doctype = decodeURIComponent($(".discussions-parent").attr("data-doctype"));
const docname = decodeURIComponent($(".discussions-parent").attr("data-docname"));
const topic = data.topic_info;
const single_thread = $(".is-single-thread").length;
const first_topic = !$(".reply-card").length;
const document_match_found = doctype == topic.reference_doctype && docname == topic.reference_docname;
if ($(`.discussion-on-page[data-topic=${data.topic_info.name}]`).length) {
if ($(`.discussion-on-page[data-topic=${topic.name}]`).length) {
post_message_cleanup();
$('<div class="card-divider-dark mb-8"></div>' + data.template).insertBefore(`.discussion-on-page[data-topic=${data.topic_info.name}] .discussion-form`);
} else if ((decodeURIComponent($(".discussions-parent .discussions-card").attr("data-doctype")) == data.topic_info.reference_doctype
&& decodeURIComponent($(".discussions-parent .discussions-card").attr("data-docname")) == data.topic_info.reference_docname)) {
data.template = style_avatar_frame(data.template);
$('<div class="card-divider-dark mb-8"></div>' + data.template)
.insertBefore(`.discussion-on-page[data-topic=${topic.name}] .discussion-form`);
} else if (!first_topic && !single_thread && document_match_found) {
post_message_cleanup();
data.new_topic_template = style_avatar_frame(data.new_topic_template);
$(data.sidebar).insertAfter(`.discussions-sidebar .form-group`);
$(`#discussion-group`).prepend(data.new_topic_template);
if (data.topic_info.owner == frappe.session.user) {
$(".discussion-on-page").collapse();
if (topic.owner == frappe.session.user) {
$(".discussion-on-page") && $(".discussion-on-page").collapse();
$(".sidebar-topic").first().click();
}
} else if (data.topic_info.owner == frappe.session.user) {
} else if (single_thread && document_match_found) {
post_message_cleanup();
data.template = style_avatar_frame(data.template);
$(data.template).insertBefore(`.discussion-form`);
$(".discussion-on-page").attr("data-topic", topic.name);
} else if (topic.owner == frappe.session.user && document_match_found) {
post_message_cleanup();
window.location.reload();
}
update_reply_count(data.topic_info.name);
update_reply_count(topic.name);
};
const post_message_cleanup = () => {
@ -191,10 +205,10 @@ const submit_discussion = (e) => {
const reply = $(".comment-field:visible").val().trim();
if (reply) {
let doctype = $(e.currentTarget).attr("data-doctype");
let doctype = $(e.currentTarget).closest(".discussions-parent").attr("data-doctype");
doctype = doctype ? decodeURIComponent(doctype) : doctype;
let docname = $(e.currentTarget).attr("data-docname");
let docname = $(e.currentTarget).closest(".discussions-parent").attr("data-docname");
docname = docname ? decodeURIComponent(docname) : docname;
frappe.call({
@ -232,7 +246,8 @@ const get_color_from_palette = (element) => {
const style_avatar_frame = (template) => {
const $template = $(template);
$template.find(".avatar-frame").css(get_color_from_palette($template.find(".avatar-frame")));
$template.find(".avatar-frame").length
&& $template.find(".avatar-frame").css(get_color_from_palette($template.find(".avatar-frame")));
return $template.prop("outerHTML");
};

View file

@ -1,22 +1,26 @@
{% set topics = frappe.get_all("Discussion Topic",
{"reference_doctype": doctype, "reference_docname": docname}, ["name", "title", "owner", "creation"]) %}
{% include "frappe/templates/discussions/topic_modal.html" %}
<div class="discussions-parent">
<div class="discussions-parent {% if single_thread %} is-single-thread {% endif %}"
data-doctype="{{ doctype | urlencode }}" data-docname="{{ docname | urlencode }}">
{% include "frappe/templates/discussions/topic_modal.html" %}
<div class="discussions-header">
<span class="course-home-headings">{{ _(title) }}</span>
{% if topics %}
{% if topics and not single_thread %}
{% include "frappe/templates/discussions/button.html" %}
{% endif %}
</div>
{% if topics %}
<div class="common-card-style thread-card discussions-card" data-doctype="{{ doctype }}"
data-docname="{{ docname }}">
<div class="common-card-style thread-card {% if topics | length and not single_thread %} discussions-card {% endif %} ">
{% if topics and not single_thread %}
<div class="discussions-sidebar">
{% include "frappe/templates/discussions/search.html" %}
{% for topic in topics %}
{% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name})%}
{% include "frappe/templates/discussions/sidebar.html" %}
@ -24,13 +28,17 @@
</div>
<div class="mr-2" id="discussion-group">
{% for topic in topics %}
{% include "frappe/templates/discussions/reply_section.html" %}
{% endfor %}
</div>
</div>
{% else %}
<div id="no-discussions" class="common-card-style thread-card">
<div class="no-discussions">
{% elif single_thread %}
{% set topic = topics[0] if topics | length else None %}
{% include "frappe/templates/discussions/reply_section.html" %}
{% else %}
<div class="no-discussions" id="no-discussions">
<div class="font-weight-bold">No {{ title }}</div>
<div class="small mt-3 mb-3">There are no {{ title | lower }} for this {{ doctype | lower }}, why don't you start
one! </div>

View file

@ -2,10 +2,10 @@
<div class="reply-card">
{% set member = frappe.db.get_value("User", reply.owner, ["name", "full_name", "username"], as_dict=True) %}
<div class="d-flex align-items-center small mb-2">
{% if loop.index == 1 %}
{% if loop.index == 1 or single_thread %}
{{ avatar(reply.owner) }}
{% endif %}
<a class="button-links {% if loop.index == 1 %} ml-2 {% endif %}" {% if get_profile_url %} href="{{ get_profile_url(member.username) }}" {% endif %}>
<a class="button-links {% if loop.index == 1 or single_thread %} ml-2 {% endif %}" {% if get_profile_url %} href="{{ get_profile_url(member.username) }}" {% endif %}>
{{ member.full_name }}
</a>
<div class="ml-3 frappe-timestamp" data-timestamp="{{ reply.creation }}"> {{ frappe.utils.pretty_date(reply.creation) }} </div>

View file

@ -1,16 +1,23 @@
{% for topic in topics %}
{% if topic %}
{% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name},
["reply", "owner", "creation"], order_by="creation")%}
{% if replies %}
<div class="collapse discussion-on-page" id="t{{ topic.name }}" data-topic="{{ topic.name }}"
data-parent="#discussion-group">
{% endif %}
<div class="collapse discussion-on-page" data-parent="#discussion-group"
{% if topic %} id="t{{ topic.name }}" data-topic="{{ topic.name }}" {% endif %}>
{% if not single_thread %}
<div class="button is-default back">
{{ _("Back") }}
</div>
{% endif %}
{% if topic and topic.title %}
<div class="course-home-headings p-0">{{ topic.title }}</div>
{% endif %}
{% for reply in replies %}
{% include "frappe/templates/discussions/reply_card.html" %}
@ -34,5 +41,3 @@
{% endif %}
</div>
{% endif %}
{% endfor %}

View file

@ -3,7 +3,7 @@
padding: 1rem;
}
.discussions-parent .form-control {
.thread-card .form-control {
background-color: #FFFFFF;
font-size: inherit;
color: inherit;
@ -246,6 +246,6 @@
}
.card-divider-dark {
border: 1px solid var(--gray-400);
margin-bottom: 16px;
border: 1px solid var(--gray-300);
margin-bottom: 1rem;
}

View file

@ -194,16 +194,17 @@ def create_form_tour():
@frappe.whitelist()
def create_data_for_discussions():
web_page = create_web_page()
web_page = create_web_page("Test page for discussions", "test-page-discussions", False)
create_topic_and_reply(web_page)
create_web_page("Test single thread discussion", "test-single-thread", True)
def create_web_page():
web_page = frappe.db.exists("Web Page", {"route": "test-page-discussions"})
def create_web_page(title, route, single_thread):
web_page = frappe.db.exists("Web Page", {"route": route})
if not web_page:
web_page = frappe.get_doc({
"doctype": "Web Page",
"title": "Test page for discussions",
"route": "test-page-discussions",
"title": title,
"route": route,
"published": True
})
web_page.save()
@ -213,7 +214,8 @@ def create_web_page():
"web_template_values": frappe.as_json({
"title": "Discussions",
"cta_title": "New Discussion",
"docname": web_page.name
"docname": web_page.name,
"single_thread": single_thread
})
})
web_page.save()

View file

@ -8,6 +8,10 @@ class DiscussionReply(Document):
def after_insert(self):
replies = frappe.db.count("Discussion Reply", {"topic": self.topic})
topic_info = frappe.get_all("Discussion Topic",
{"name": self.topic},
["reference_doctype", "reference_docname", "name", "title", "owner", "creation"])
template = frappe.render_template("frappe/templates/discussions/reply_card.html", {
"reply": self,
"topic": {
@ -15,19 +19,16 @@ class DiscussionReply(Document):
},
"loop": {
"index": replies
}
},
"single_thread": True if not topic_info[0].title else False
})
topic_info = frappe.get_all("Discussion Topic",
{"name": self.topic},
["reference_doctype", "reference_docname", "name", "title", "owner", "creation"])
sidebar = frappe.render_template("frappe/templates/discussions/sidebar.html", {
"topic": topic_info[0]
})
new_topic_template = frappe.render_template("frappe/templates/discussions/reply_section.html", {
"topics": topic_info
"topic": topic_info[0]
})
frappe.publish_realtime(

View file

@ -22,10 +22,17 @@
"label": "Web Page",
"options": "Web Page",
"reqd": 1
},
{
"__unsaved": 1,
"fieldname": "single_thread",
"fieldtype": "Check",
"label": "Single Thread",
"reqd": 0
}
],
"idx": 0,
"modified": "2021-10-01 12:15:28.876920",
"modified": "2021-10-01 15:15:57.366552",
"modified_by": "Administrator",
"module": "Website",
"name": "Discussions",
@ -33,4 +40,4 @@
"standard": 1,
"template": "",
"type": "Section"
}
}