Merge pull request #14380 from pateljannat/discussions-single-topic
This commit is contained in:
commit
828d158e4d
10 changed files with 126 additions and 69 deletions
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue