Skip to content

Commit 85467d4

Browse files
authored
Merge pull request #8515 from sagemathinc/chat-copy-button
frontend/chat: add mini button to copy markdown to clipboard
2 parents a3ac554 + d4bfedc commit 85467d4

File tree

19 files changed

+560
-108
lines changed

19 files changed

+560
-108
lines changed

src/packages/frontend/chat/message.tsx

Lines changed: 115 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Badge, Button, Col, Popconfirm, Row, Space, Tooltip } from "antd";
99
import { List, Map } from "immutable";
1010
import { CSSProperties, useEffect, useLayoutEffect } from "react";
1111
import { useIntl } from "react-intl";
12+
1213
import { Avatar } from "@cocalc/frontend/account/avatar/avatar";
1314
import {
1415
CSS,
@@ -19,6 +20,7 @@ import {
1920
useTypedRedux,
2021
} from "@cocalc/frontend/app-framework";
2122
import { Gap, Icon, TimeAgo, Tip } from "@cocalc/frontend/components";
23+
import CopyButton from "@cocalc/frontend/components/copy-button";
2224
import MostlyStaticMarkdown from "@cocalc/frontend/editors/slate/mostly-static-markdown";
2325
import { IS_TOUCH } from "@cocalc/frontend/feature";
2426
import { modelToName } from "@cocalc/frontend/frame-editors/llm/llm-selector";
@@ -501,14 +503,122 @@ export default function Message({
501503
);
502504
}
503505

504-
function renderMessageBody({ lighten, message_class }) {
505-
const value = newest_content(message);
506+
function renderCopyMessageButton() {
507+
return (
508+
<Tip
509+
placement={"top"}
510+
title={intl.formatMessage({
511+
id: "chat.message.copy_markdown.tooltip",
512+
defaultMessage: "Copy message as markdown",
513+
description:
514+
"Tooltip for button to copy chat message as markdown text",
515+
})}
516+
>
517+
<CopyButton
518+
value={message_to_markdown(message)}
519+
size="small"
520+
noText={true}
521+
style={{
522+
color: is_viewers_message ? "white" : "#888",
523+
fontSize: "12px",
524+
marginTop: "-4px",
525+
}}
526+
/>
527+
</Tip>
528+
);
529+
}
530+
531+
function renderLinkMessageButton() {
532+
return (
533+
<Tip
534+
placement={"top"}
535+
title={intl.formatMessage({
536+
id: "chat.message.copy_link.tooltip",
537+
defaultMessage: "Select message. Copy URL to link to this message.",
538+
description:
539+
"Tooltip for button to copy URL link to specific chat message",
540+
})}
541+
>
542+
<Button
543+
onClick={() => {
544+
actions?.setFragment(message.get("date"));
545+
}}
546+
size="small"
547+
type={"text"}
548+
style={{
549+
color: is_viewers_message ? "white" : "#888",
550+
fontSize: "12px",
551+
marginTop: "-4px",
552+
}}
553+
>
554+
<Icon name="link" />
555+
</Button>
556+
</Tip>
557+
);
558+
}
559+
560+
function renderLLMFeedbackButtons() {
561+
if (isLLMThread) return;
506562

507563
const feedback = message.getIn(["feedback", account_id]);
508564
const otherFeedback =
509565
isLLMThread && msgWrittenByLLM ? 0 : (message.get("feedback")?.size ?? 0);
510566
const showOtherFeedback = otherFeedback > 0;
511567

568+
return (
569+
<Tip
570+
placement={"top"}
571+
title={
572+
!showOtherFeedback
573+
? "Like this"
574+
: () => {
575+
return (
576+
<div>
577+
{Object.keys(message.get("feedback")?.toJS() ?? {}).map(
578+
(account_id) => (
579+
<div key={account_id} style={{ marginBottom: "2px" }}>
580+
<Avatar size={24} account_id={account_id} />{" "}
581+
<User account_id={account_id} />
582+
</div>
583+
),
584+
)}
585+
</div>
586+
);
587+
}
588+
}
589+
>
590+
<Button
591+
style={{
592+
color: !feedback && is_viewers_message ? "white" : "#888",
593+
fontSize: "12px",
594+
marginTop: "-4px",
595+
...(feedback ? {} : { position: "relative", top: "-5px" }),
596+
}}
597+
size="small"
598+
type={feedback ? "dashed" : "text"}
599+
onClick={() => {
600+
actions?.feedback(message, feedback ? null : "positive");
601+
}}
602+
>
603+
{showOtherFeedback ? (
604+
<Badge count={otherFeedback} color="darkblue" size="small" />
605+
) : (
606+
""
607+
)}
608+
<Icon
609+
name="thumbs-up"
610+
style={{
611+
color: showOtherFeedback ? "darkblue" : undefined,
612+
}}
613+
/>
614+
</Button>
615+
</Tip>
616+
);
617+
}
618+
619+
function renderMessageBody({ lighten, message_class }) {
620+
const value = newest_content(message);
621+
512622
return (
513623
<>
514624
<span style={lighten}>
@@ -518,81 +628,9 @@ export default function Message({
518628
align="baseline"
519629
style={{ float: "right", marginRight: "10px" }}
520630
>
521-
{!isLLMThread && (
522-
<Tip
523-
placement={"top"}
524-
title={
525-
!showOtherFeedback
526-
? "Like this"
527-
: () => {
528-
return (
529-
<div>
530-
{Object.keys(
531-
message.get("feedback")?.toJS() ?? {},
532-
).map((account_id) => (
533-
<div
534-
key={account_id}
535-
style={{ marginBottom: "2px" }}
536-
>
537-
<Avatar size={24} account_id={account_id} />{" "}
538-
<User account_id={account_id} />
539-
</div>
540-
))}
541-
</div>
542-
);
543-
}
544-
}
545-
>
546-
<Button
547-
style={{
548-
color: !feedback && is_viewers_message ? "white" : "#888",
549-
fontSize: "12px",
550-
marginTop: "-4px",
551-
...(feedback ? {} : { position: "relative", top: "-5px" }),
552-
}}
553-
size="small"
554-
type={feedback ? "dashed" : "text"}
555-
onClick={() => {
556-
actions?.feedback(message, feedback ? null : "positive");
557-
}}
558-
>
559-
{showOtherFeedback ? (
560-
<Badge
561-
count={otherFeedback}
562-
color="darkblue"
563-
size="small"
564-
/>
565-
) : (
566-
""
567-
)}
568-
<Icon
569-
name="thumbs-up"
570-
style={{
571-
color: showOtherFeedback ? "darkblue" : undefined,
572-
}}
573-
/>
574-
</Button>
575-
</Tip>
576-
)}
577-
<Tip
578-
placement={"top"}
579-
title="Select message. Copy URL to link to this message."
580-
>
581-
<Button
582-
onClick={() => {
583-
actions?.setFragment(message.get("date"));
584-
}}
585-
size="small"
586-
type={"text"}
587-
style={{
588-
color: is_viewers_message ? "white" : "#888",
589-
fontSize: "12px",
590-
marginTop: "-4px",
591-
}}
592-
>
593-
<Icon name="link" />
594-
</Button>
595-
</Tip>
631+
{renderLLMFeedbackButtons()}
632+
{renderCopyMessageButton()}
633+
{renderLinkMessageButton()}
596634
</Space>
597635
</span>
598636
<MostlyStaticMarkdown

src/packages/frontend/i18n/trans/ar_EG.json

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@
135135
"app.verify-email-banner.title": "تحقق من عنوان بريدك الإلكتروني",
136136
"chat.chat-indicator.tooltip": "إخفاء أو إظهار محادثة المستندات",
137137
"chat.input.placeholder": "اكتب رسالة جديدة ({have_llm, select, true {الدردشة مع الذكاء الاصطناعي أو } other {}}إخطار زميل بكتابة @)...",
138+
"chat.message.copy_link.tooltip": "حدد الرسالة. انسخ عنوان URL للربط بهذه الرسالة.",
139+
"chat.message.copy_markdown.tooltip": "نسخ الرسالة كنص تنسيق Markdown",
138140
"chatroom.chat_input.preview_button.label": "عرض",
139141
"chatroom.chat_input.send_button.label": "إرسال",
140142
"chatroom.chat_input.send_button.tooltip": "إرسال رسالة (shift+enter)",
@@ -634,8 +636,10 @@
634636
"jupyter.cell-buttonbar-menu.paste-cell-below": "لصق الخلية أدناه",
635637
"jupyter.cell-buttonbar-menu.paste-clipboard": "لصق من الحافظة",
636638
"jupyter.cell-buttonbar-menu.split-cell": "قسّم الخلية عند المؤشر",
639+
"jupyter.cell-buttonbar.format-button.label": "تنسيق",
640+
"jupyter.cell-buttonbar.format-button.tooltip": "نسّق هذا الكود ليبدو جميلاً",
637641
"jupyter.cell-buttonbr.format-button.label": "تنسيق",
638-
"jupyter.cell-buttonbr.format-button.tooltip": "نسّق هذا الكود ليبدو جميلاً",
642+
"jupyter.cell-buttonbr.format-button.tooltip": "نسق هذا الكود ليبدو جميلاً",
639643
"jupyter.commands.cell_toolbar_attachments.label": "شريط أدوات المرفقات",
640644
"jupyter.commands.cell_toolbar_attachments.menu": "المرفقات",
641645
"jupyter.commands.cell_toolbar_create_assignment.label": "إنشاء واجب باستخدام NBgrader",
@@ -812,6 +816,8 @@
812816
"jupyter.editor.run_all_cells.label": "تشغيل جميع الخلايا",
813817
"jupyter.editor.run_selected_cells.label": "تشغيل الخلايا المحددة",
814818
"jupyter.editor.snippets_tooltip": "افتح لوحة تحتوي على مقتطفات الكود",
819+
"jupyter.llm.cell-tool.actions.ask.descr": "اطرح سؤالاً مخصصاً حول الكود في هذه الخلية.",
820+
"jupyter.llm.cell-tool.actions.ask.label": "اسأل",
815821
"jupyter.llm.cell-tool.actions.bugfix.descr": "وصف مشكلة تلك الخلية للحصول على نسخة مصححة من الخطأ",
816822
"jupyter.llm.cell-tool.actions.bugfix.label": "إصلاح الأخطاء",
817823
"jupyter.llm.cell-tool.actions.document.descr": "إضافة التوثيق",
@@ -820,22 +826,39 @@
820826
"jupyter.llm.cell-tool.actions.explain.label": "اشرح",
821827
"jupyter.llm.cell-tool.actions.improve.descr": "حسّن الشيفرة في تلك الخلية",
822828
"jupyter.llm.cell-tool.actions.improve.label": "تحسين",
829+
"jupyter.llm.cell-tool.actions.md.ask.descr": "اطرح سؤالًا مخصصًا حول هذه الخلية مع سياق اختياري من الخلايا المحيطة.",
830+
"jupyter.llm.cell-tool.actions.md.document.descr": "اكتب ملخصًا حول جميع الخلايا في السياق",
831+
"jupyter.llm.cell-tool.actions.md.document.label": "توثيق",
832+
"jupyter.llm.cell-tool.actions.md.formulize.descr": "أضف صيغًا رياضية لجعل النص أكثر قابلية للقراءة للعلماء.",
833+
"jupyter.llm.cell-tool.actions.md.formulize.label": "إضافة صيغ",
834+
"jupyter.llm.cell-tool.actions.md.proofread.descr": "تحسين اللغة، إصلاح الأخطاء الإملائية والنحوية.",
835+
"jupyter.llm.cell-tool.actions.md.proofread.label": "تدقيق",
836+
"jupyter.llm.cell-tool.actions.md.translate-text.descr": "ترجمة محتوى النص إلى لغة بشرية أخرى.",
837+
"jupyter.llm.cell-tool.actions.md.translate-text.label": "ترجمة",
823838
"jupyter.llm.cell-tool.actions.modify.descr": "عدل الكود في الخلية",
824839
"jupyter.llm.cell-tool.actions.modify.label": "تعديل",
825840
"jupyter.llm.cell-tool.actions.translate.descr": "ترجمة الشيفرة في تلك الخلية إلى لغة أخرى باستخدام الذكاء الاصطناعي.",
826841
"jupyter.llm.cell-tool.actions.translate.label": "ترجمة",
842+
"jupyter.llm.cell-tool.ask.label": "سؤال",
843+
"jupyter.llm.cell-tool.ask.placeholder": "ماذا تريد أن تعرف عن هذا الرمز؟",
827844
"jupyter.llm.cell-tool.assistant.title": "استخدم مساعد الذكاء الاصطناعي على هذه الخلية",
828845
"jupyter.llm.cell-tool.bugfix.label": "خلل",
829846
"jupyter.llm.cell-tool.bugfix.placeholder": "صف المشكلة التي تحتاج إلى إصلاحها...",
847+
"jupyter.llm.cell-tool.document.label": "تركيز",
848+
"jupyter.llm.cell-tool.document.placeholder": "على ماذا يجب أن تركز الوثائق؟ (اختياري)",
830849
"jupyter.llm.cell-tool.explain.description": "كيف تشرح الشيفرة؟ إما {summary} عالي المستوى أو {step_by_step} تفسيرات.",
831850
"jupyter.llm.cell-tool.explain.step-by-step": "خطوة بخطوة",
832851
"jupyter.llm.cell-tool.explain.summary": "ملخص",
852+
"jupyter.llm.cell-tool.explanation.ask": "اطرح أي سؤال حول الكود في هذه الخلية. سيقوم نموذج اللغة بتحليل الكود وتقديم إجابة بناءً على سؤالك المحدد.",
833853
"jupyter.llm.cell-tool.explanation.bugfix": "اشرح مشكلة الكود في الخلية وسيحاول النموذج اللغوي المحدد إصلاحها. عادةً، سيخبرك إذا وجد مشكلة ويشرحها لك.",
834854
"jupyter.llm.cell-tool.explanation.document": "سيقوم نموذج اللغة بإضافة سطور التوثيق إلى الكود في الخلية.",
835855
"jupyter.llm.cell-tool.explanation.explain": "سيتم إرسال الكود في الخلية إلى النموذج اللغوي المحدد. سيوضح لك الكود بلغة بسيطة.",
836-
"jupyter.llm.cell-tool.explanation.improve": "سيقوم نموذج اللغة المحدد بتحليل الكود واقتراح التحسينات. احذر، فالنتائج ليست مضمونة أن تكون صحيحة، وقد تسبب مشكلات دقيقة - راجعها بعناية.",
856+
"jupyter.llm.cell-tool.explanation.formulize": "سيضيف نموذج اللغة الصيغ الرياضية المناسبة باستخدام ترميز LaTeX لجعل النص أكثر وضوحًا للعلماء.",
857+
"jupyter.llm.cell-tool.explanation.improve": "سيقوم نموذج اللغة المحدد بتحليل الشفرة واقتراح تحسينات. احذر، فالنتائج لا يُضمن أن تكون صحيحة، وقد تسبب مشاكل طفيفة – راجعها بعناية.",
837858
"jupyter.llm.cell-tool.explanation.modify": "سيقوم نموذج اللغة بتعديل الكود وفقًا للتعليمات المعطاة. اختر أحد النماذج وقم بتعديله، أو ابتكر تعليمات خاصة بك!",
859+
"jupyter.llm.cell-tool.explanation.proofread": "سيقوم نموذج اللغة بمراجعة نص الماركداون، وتصحيح الأخطاء الإملائية والنحوية مع تحسين الوضوح وسهولة القراءة.",
838860
"jupyter.llm.cell-tool.explanation.translate": "سيحاول نموذج اللغة ترجمة الكود في الخلية إلى لغة برمجة أخرى. قد لا يعمل الناتج على الإطلاق - ولكن إذا كنت أكثر دراية بلغة الهدف المختارة، فقد تجد من الأسهل فهم ما يحدث!",
861+
"jupyter.llm.cell-tool.explanation.translate-text": "سيقوم نموذج اللغة بترجمة نصوص الماركداون إلى اللغة المحددة مع الحفاظ على التنسيق والهيكل.",
839862
"jupyter.llm.cell-tool.footer.info": "إرسال هذه الرسالة إلى {model} سيبدأ محادثة في <A>إطار الدردشة الجانبية</A>. سيرد نموذج اللغة ويمكنك متابعة المحادثة في نفس الموضوع.",
840863
"jupyter.llm.cell-tool.improve.label": "تحسين",
841864
"jupyter.llm.cell-tool.improve.placeholder": "سرعة التنفيذ، القابلية للقراءة، …",

0 commit comments

Comments
 (0)