mirror of https://github.com/zulip/zulip.git
parent
ff52187289
commit
043d54d170
|
@ -109,6 +109,7 @@
|
|||
<div id="manage_streams_container"></div>
|
||||
<div id="manage_groups_container"></div>
|
||||
<div id="drafts_table"></div>
|
||||
<div id="scheduled_messages_overlay_container"></div>
|
||||
<div id="settings_overlay_container" class="overlay" data-overlay="settings" aria-hidden="true">
|
||||
</div>
|
||||
|
||||
|
|
|
@ -144,6 +144,8 @@ EXEMPT_FILES = make_set(
|
|||
"web/src/reminder.js",
|
||||
"web/src/resize.js",
|
||||
"web/src/rows.js",
|
||||
"web/src/scheduled_messages.js",
|
||||
"web/src/scheduled_messages_overlay_ui.js",
|
||||
"web/src/scroll_bar.ts",
|
||||
"web/src/search_pill_widget.js",
|
||||
"web/src/sent_messages.js",
|
||||
|
|
|
@ -38,6 +38,7 @@ import "../../styles/modal.css";
|
|||
import "../../styles/settings.css";
|
||||
import "../../styles/image_upload_widget.css";
|
||||
import "../../styles/subscriptions.css";
|
||||
import "../../styles/scheduled_messages.css";
|
||||
import "../../styles/drafts.css";
|
||||
import "../../styles/input_pill.css";
|
||||
import "../../styles/informational_overlays.css";
|
||||
|
|
|
@ -15,6 +15,7 @@ export const ERROR = "error";
|
|||
const MESSAGE_SENT_CLASSNAMES = {
|
||||
sent_scroll_to_view: "sent_scroll_to_view",
|
||||
narrow_to_recipient: "narrow_to_recipient",
|
||||
scheduled_message_banner: "scheduled_message_banner",
|
||||
};
|
||||
|
||||
export const CLASSNAMES = {
|
||||
|
|
|
@ -208,6 +208,7 @@ export function is_overlay_hash(hash) {
|
|||
"message-formatting",
|
||||
"search-operators",
|
||||
"about-zulip",
|
||||
"scheduled",
|
||||
];
|
||||
const main_hash = get_hash_category(hash);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import * as overlays from "./overlays";
|
|||
import {page_params} from "./page_params";
|
||||
import * as recent_topics_ui from "./recent_topics_ui";
|
||||
import * as recent_topics_util from "./recent_topics_util";
|
||||
import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui";
|
||||
import * as search from "./search";
|
||||
import * as settings from "./settings";
|
||||
import * as settings_panel_menu from "./settings_panel_menu";
|
||||
|
@ -212,6 +213,7 @@ function do_hashchange_normal(from_reload) {
|
|||
case "#organization":
|
||||
case "#settings":
|
||||
case "#about-zulip":
|
||||
case "#scheduled":
|
||||
blueslip.error("overlay logic skipped for: " + hash);
|
||||
break;
|
||||
default:
|
||||
|
@ -368,6 +370,10 @@ function do_hashchange_overlay(old_hash) {
|
|||
if (base === "about-zulip") {
|
||||
about_zulip.launch();
|
||||
}
|
||||
|
||||
if (base === "scheduled") {
|
||||
scheduled_messages_overlay_ui.launch();
|
||||
}
|
||||
}
|
||||
|
||||
function hashchanged(from_reload, e) {
|
||||
|
|
|
@ -85,6 +85,10 @@ export function drafts_open(): boolean {
|
|||
return open_overlay_name === "drafts";
|
||||
}
|
||||
|
||||
export function scheduled_messages_open(): boolean {
|
||||
return open_overlay_name === "scheduled";
|
||||
}
|
||||
|
||||
export function active_modal(): string | undefined {
|
||||
if (!is_modal_open()) {
|
||||
blueslip.error("Programming error — Called active_modal when there is no modal open");
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
import $ from "jquery";
|
||||
|
||||
import * as channel from "./channel";
|
||||
import * as compose from "./compose";
|
||||
import * as compose_actions from "./compose_actions";
|
||||
import * as compose_fade from "./compose_fade";
|
||||
import * as compose_ui from "./compose_ui";
|
||||
import * as narrow from "./narrow";
|
||||
import * as overlays from "./overlays";
|
||||
import * as people from "./people";
|
||||
import * as popover_menus from "./popover_menus";
|
||||
|
||||
// This is only updated when user opens the scheduled messages overlay.
|
||||
export let scheduled_messages_data = [];
|
||||
|
||||
export function override_scheduled_messages_data(data) {
|
||||
scheduled_messages_data = data;
|
||||
}
|
||||
|
||||
export function edit_scheduled_message(scheduled_msg_id) {
|
||||
const scheduled_msg = scheduled_messages_data.find(
|
||||
(msg) => msg.message_id === scheduled_msg_id,
|
||||
);
|
||||
|
||||
let compose_args;
|
||||
|
||||
if (scheduled_msg.type === "stream") {
|
||||
compose_args = {
|
||||
type: "stream",
|
||||
stream: scheduled_msg.stream_name,
|
||||
topic: scheduled_msg.topic,
|
||||
content: scheduled_msg.content,
|
||||
};
|
||||
} else {
|
||||
const recipient_emails = [];
|
||||
if (scheduled_msg.to) {
|
||||
for (const recipient_id of scheduled_msg.to) {
|
||||
recipient_emails.push(people.get_by_user_id(recipient_id).email);
|
||||
}
|
||||
}
|
||||
compose_args = {
|
||||
type: scheduled_msg.type,
|
||||
private_message_recipient: recipient_emails.join(","),
|
||||
content: scheduled_msg.content,
|
||||
};
|
||||
}
|
||||
|
||||
if (compose_args.type === "stream") {
|
||||
narrow.activate(
|
||||
[
|
||||
{operator: "stream", operand: compose_args.stream},
|
||||
{operator: "topic", operand: compose_args.topic},
|
||||
],
|
||||
{trigger: "edit scheduled message"},
|
||||
);
|
||||
} else {
|
||||
narrow.activate([{operator: "pm-with", operand: compose_args.private_message_recipient}], {
|
||||
trigger: "edit scheduled message",
|
||||
});
|
||||
}
|
||||
|
||||
overlays.close_overlay("scheduled");
|
||||
compose_fade.clear_compose();
|
||||
compose.clear_preview_area();
|
||||
compose_actions.start(compose_args.type, compose_args);
|
||||
compose_ui.autosize_textarea($("#compose-textarea"));
|
||||
$("#compose-textarea").attr("data-scheduled-message-id", scheduled_msg_id);
|
||||
popover_menus.show_schedule_confirm_button(scheduled_msg.formatted_send_at_time, true);
|
||||
}
|
||||
|
||||
export function delete_scheduled_message(scheduled_msg_id) {
|
||||
channel.del({
|
||||
url: "/json/scheduled_messages/" + scheduled_msg_id,
|
||||
success() {
|
||||
// TODO: Do this via events received from the server in server_events_dispatch.
|
||||
if (overlays.scheduled_messages_open()) {
|
||||
$(
|
||||
`#scheduled_messages_overlay .scheduled-message-row[data-message-id=${scheduled_msg_id}]`,
|
||||
).remove();
|
||||
}
|
||||
if ($("#compose-textarea").attr("data-scheduled-message-id")) {
|
||||
const compose_scheduled_msg_id = $("#compose-textarea").attr(
|
||||
"data-scheduled-message-id",
|
||||
);
|
||||
// If user deleted the scheduled message which is being edited in compose, we clear
|
||||
// the scheduled message id from there which converts this editing state into a normal
|
||||
// schedule message state. So, clicking "Schedule" will now create a new scheduled message.
|
||||
if (compose_scheduled_msg_id === scheduled_msg_id) {
|
||||
$("#compose-textarea").removeAttr("data-scheduled-message-id");
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function delete_scheduled_message_if_sent_directly() {
|
||||
// Delete old scheduled message if it was sent.
|
||||
if ($("#compose-textarea").attr("data-scheduled-message-id")) {
|
||||
delete_scheduled_message($("#compose-textarea").attr("data-scheduled-message-id"));
|
||||
$("#compose-textarea").removeAttr("data-scheduled-message-id");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
import * as date_fns from "date-fns";
|
||||
import $ from "jquery";
|
||||
|
||||
import render_scheduled_message from "../templates/scheduled_message.hbs";
|
||||
import render_scheduled_messages_overlay from "../templates/scheduled_messages_overlay.hbs";
|
||||
|
||||
import * as blueslip from "./blueslip";
|
||||
import * as browser_history from "./browser_history";
|
||||
import * as channel from "./channel";
|
||||
import * as loading from "./loading";
|
||||
import * as overlays from "./overlays";
|
||||
import * as people from "./people";
|
||||
import * as scheduled_messages from "./scheduled_messages";
|
||||
import * as stream_color from "./stream_color";
|
||||
import * as stream_data from "./stream_data";
|
||||
import * as timerender from "./timerender";
|
||||
|
||||
function hide_loading_indicator() {
|
||||
loading.destroy_indicator($("#scheduled_messages_overlay .loading-indicator"));
|
||||
$(".scheduled-messages-loading").hide();
|
||||
}
|
||||
|
||||
function format(scheduled_messages) {
|
||||
const formatted_msgs = [];
|
||||
for (const msg of scheduled_messages) {
|
||||
const msg_render_context = {...msg};
|
||||
if (msg.type === "stream") {
|
||||
msg_render_context.is_stream = true;
|
||||
msg_render_context.stream_id = msg.to[0];
|
||||
msg_render_context.stream_name = stream_data.maybe_get_stream_name(
|
||||
msg_render_context.stream_id,
|
||||
);
|
||||
const color = stream_data.get_color(msg_render_context.stream_name);
|
||||
msg_render_context.recipient_bar_color = stream_color.get_recipient_bar_color(color);
|
||||
msg_render_context.stream_privacy_icon_color =
|
||||
stream_color.get_stream_privacy_icon_color(color);
|
||||
} else {
|
||||
msg_render_context.is_stream = false;
|
||||
msg_render_context.recipients = people.get_recipients(msg.to.join(","));
|
||||
}
|
||||
const time = new Date(msg.deliver_at);
|
||||
msg_render_context.full_date_time = timerender.get_full_datetime(time);
|
||||
msg_render_context.formatted_send_at_time = date_fns.format(time, "MMM d yyyy h:mm a");
|
||||
formatted_msgs.push(msg_render_context);
|
||||
}
|
||||
return formatted_msgs;
|
||||
}
|
||||
|
||||
export function launch() {
|
||||
$("#scheduled_messages_overlay_container").empty();
|
||||
$("#scheduled_messages_overlay_container").append(render_scheduled_messages_overlay());
|
||||
overlays.open_overlay({
|
||||
name: "scheduled",
|
||||
$overlay: $("#scheduled_messages_overlay"),
|
||||
on_close() {
|
||||
browser_history.exit_overlay();
|
||||
},
|
||||
});
|
||||
loading.make_indicator($("#scheduled_messages_overlay .loading-indicator"), {
|
||||
abs_positioned: true,
|
||||
});
|
||||
|
||||
channel.get({
|
||||
url: "/json/scheduled_messages",
|
||||
success(data) {
|
||||
hide_loading_indicator();
|
||||
if (data.scheduled_messages.length === 0) {
|
||||
$(".no-overlay-messages").show();
|
||||
} else {
|
||||
// Saving formatted data is helpful when user is trying to edit a scheduled message.
|
||||
scheduled_messages.override_scheduled_messages_data(
|
||||
format(data.scheduled_messages),
|
||||
);
|
||||
const rendered_list = render_scheduled_message({
|
||||
scheduled_messages_data: scheduled_messages.scheduled_messages_data,
|
||||
});
|
||||
const $messages_list = $("#scheduled_messages_overlay .overlay-messages-list");
|
||||
$messages_list.append(rendered_list);
|
||||
}
|
||||
},
|
||||
error(xhr) {
|
||||
hide_loading_indicator();
|
||||
blueslip.error(xhr);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function initialize() {
|
||||
$("body").on("click", ".scheduled-message-row .restore-overlay-message", (e) => {
|
||||
let scheduled_msg_id = $(e.currentTarget)
|
||||
.closest(".scheduled-message-row")
|
||||
.attr("data-message-id");
|
||||
scheduled_msg_id = Number.parseInt(scheduled_msg_id, 10);
|
||||
scheduled_messages.edit_scheduled_message(scheduled_msg_id);
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$("body").on("click", ".scheduled-message-row .delete-overlay-message", (e) => {
|
||||
const scheduled_msg_id = $(e.currentTarget)
|
||||
.closest(".scheduled-message-row")
|
||||
.attr("data-message-id");
|
||||
scheduled_messages.delete_scheduled_message(scheduled_msg_id);
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
|
@ -72,6 +72,7 @@ import * as reload from "./reload";
|
|||
import * as rendered_markdown from "./rendered_markdown";
|
||||
import * as resize from "./resize";
|
||||
import * as rows from "./rows";
|
||||
import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui";
|
||||
import * as scroll_bar from "./scroll_bar";
|
||||
import * as search from "./search";
|
||||
import * as search_pill_widget from "./search_pill_widget";
|
||||
|
@ -647,6 +648,7 @@ export function initialize_everything() {
|
|||
spoilers.initialize();
|
||||
lightbox.initialize();
|
||||
click_handlers.initialize();
|
||||
scheduled_messages_overlay_ui.initialize();
|
||||
copy_and_paste.initialize();
|
||||
overlays.initialize();
|
||||
invite.initialize();
|
||||
|
|
|
@ -1264,6 +1264,7 @@
|
|||
background-color: hsl(212deg 28% 18%);
|
||||
}
|
||||
|
||||
.scheduled-messages-loading-logo,
|
||||
.alert-zulip-logo,
|
||||
.top-messages-logo,
|
||||
.bottom-messages-logo {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#scheduled_messages_overlay_container {
|
||||
.scheduled-messages-loading {
|
||||
margin-top: 10px;
|
||||
display: grid;
|
||||
|
||||
> * {
|
||||
grid-row-start: 1;
|
||||
grid-column-start: 1;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.no-overlay-messages {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -201,6 +201,7 @@ p.n-margin {
|
|||
padding-top: var(--header-padding-bottom);
|
||||
}
|
||||
|
||||
.scheduled-messages-loading-logo,
|
||||
.alert-zulip-logo,
|
||||
.top-messages-logo,
|
||||
.bottom-messages-logo {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
{{#each scheduled_messages_data}}
|
||||
<div class="scheduled-message-row overlay-message-row" data-message-id="{{message_id}}">
|
||||
<div class="overlay-message-info-box" tabindex="0">
|
||||
{{#if is_stream}}
|
||||
<div class="message_header message_header_stream">
|
||||
<div class="message-header-contents" style="background: {{recipient_bar_color}};">
|
||||
<div class="message_label_clickable stream_label">
|
||||
<span class="stream-privacy-modified-color-{{stream_id}} stream-privacy filter-icon" style="color: {{stream_privacy_icon_color}}">
|
||||
{{> stream_privacy}}
|
||||
</span>
|
||||
{{stream_name}}
|
||||
</div>
|
||||
<span class="stream_topic_separator"><i class="zulip-icon zulip-icon-chevron-right"></i></span>
|
||||
<span class="stream_topic">
|
||||
<div class="message_label_clickable narrows_by_topic">
|
||||
{{topic}}
|
||||
</div>
|
||||
</span>
|
||||
<span class="recipient_bar_controls"></span>
|
||||
<div class="recipient_row_date">{{ formatted_send_at_time }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="message_header message_header_private_message">
|
||||
<div class="message-header-contents">
|
||||
<div class="message_label_clickable stream_label">
|
||||
<span class="private_message_header_icon"><i class="zulip-icon zulip-icon-user"></i></span>
|
||||
{{t "You and {recipients}" }}
|
||||
</div>
|
||||
<div class="recipient_row_date">{{ formatted_send_at_time }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="message_row{{^is_stream}} private-message{{/is_stream}}" role="listitem">
|
||||
<div class="messagebox">
|
||||
<div class="messagebox-content">
|
||||
<div class="message_top_line">
|
||||
<div class="overlay_message_controls">
|
||||
<i class="fa fa-pencil fa-lg restore-overlay-message tippy-zulip-tooltip" aria-hidden="true" data-tooltip-template-id="restore-scheduled-message-tooltip-template"></i>
|
||||
<template id="restore-scheduled-message-tooltip-template">
|
||||
{{t 'Edit or reschedule message' }}
|
||||
{{tooltip_hotkey_hints "Enter"}}
|
||||
</template>
|
||||
<i class="fa fa-trash-o fa-lg delete-overlay-message tippy-zulip-tooltip" aria-hidden="true" data-tooltip-template-id="delete-scheduled-message-tooltip-template"></i>
|
||||
<template id="delete-scheduled-message-tooltip-template">
|
||||
{{t 'Delete scheduled message' }}
|
||||
{{tooltip_hotkey_hints "Backspace"}}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="message_content rendered_markdown restore-overlay-message" title="{{t 'Edit or reschedule message' }}">{{rendered_markdown rendered_content}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
|
@ -0,0 +1,32 @@
|
|||
<div id="scheduled_messages_overlay" class="overlay new-style" data-overlay="scheduled">
|
||||
<div class="flex overlay-content">
|
||||
<div class="overlay-messages-container modal-bg">
|
||||
<div class="overlay-messages-header">
|
||||
<h1>{{t 'Scheduled messages' }}</h1>
|
||||
<div class="exit">
|
||||
<span class="exit-sign">×</span>
|
||||
</div>
|
||||
<div class="removed-drafts">
|
||||
{{#tr}}
|
||||
Click on the pencil (<z-pencil-icon></z-pencil-icon>) icon to reschedule a message.
|
||||
{{#*inline "z-pencil-icon"}}<i class="fa fa-pencil"></i>{{/inline}}
|
||||
{{/tr}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="scheduled-messages-loading">
|
||||
<div class="scheduled-messages-loading-logo">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 773.12 773.12">
|
||||
<circle cx="386.56" cy="386.56" r="386.56"></circle>
|
||||
<path d="M566.66 527.25c0 33.03-24.23 60.05-53.84 60.05H260.29c-29.61 0-53.84-27.02-53.84-60.05 0-20.22 9.09-38.2 22.93-49.09l134.37-120c2.5-2.14 5.74 1.31 3.94 4.19l-49.29 98.69c-1.38 2.76.41 6.16 3.25 6.16h191.18c29.61 0 53.83 27.03 53.83 60.05zm0-281.39c0 20.22-9.09 38.2-22.93 49.09l-134.37 120c-2.5 2.14-5.74-1.31-3.94-4.19l49.29-98.69c1.38-2.76-.41-6.16-3.25-6.16H260.29c-29.61 0-53.84-27.02-53.84-60.05s24.23-60.05 53.84-60.05h252.54c29.61 0 53.83 27.02 53.83 60.05z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="loading-indicator"></div>
|
||||
</div>
|
||||
<div class="overlay-messages-list">
|
||||
<div class="no-overlay-messages">
|
||||
{{t 'No scheduled messages.'}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue