diff --git a/web/src/stream_create.ts b/web/src/stream_create.ts
index 2f58be4d7d..89a26bd3fb 100644
--- a/web/src/stream_create.ts
+++ b/web/src/stream_create.ts
@@ -3,9 +3,11 @@ import assert from "minimalistic-assert";
import {z} from "zod";
import render_subscription_invites_warning_modal from "../templates/confirm_dialog/confirm_subscription_invites_warning.hbs";
+import render_change_stream_info_modal from "../templates/stream_settings/change_stream_info_modal.hbs";
import * as channel from "./channel";
import * as confirm_dialog from "./confirm_dialog";
+import * as dialog_widget from "./dialog_widget";
import {$t, $t_html} from "./i18n";
import * as keydown_util from "./keydown_util";
import * as loading from "./loading";
@@ -16,6 +18,7 @@ import {current_user, realm} from "./state_data";
import * as stream_create_subscribers from "./stream_create_subscribers";
import * as stream_data from "./stream_data";
import * as stream_settings_components from "./stream_settings_components";
+import * as stream_settings_data from "./stream_settings_data";
import * as stream_ui_updates from "./stream_ui_updates";
import type {HTMLSelectOneElement} from "./types";
import * as ui_report from "./ui_report";
@@ -58,6 +61,12 @@ export function should_show_first_stream_created_modal(): boolean {
return onboarding_steps.ONE_TIME_NOTICES_TO_DISPLAY.has("first_stream_created_banner");
}
+export function maybe_update_error_message(): void {
+ if ($("#stream_name_error").is(":visible") && $("#archived_stream_rename").is(":visible")) {
+ $("#create_stream_name").trigger("input");
+ }
+}
+
class StreamSubscriptionError {
report_no_subs_to_stream(): void {
$("#stream_subscription_error").text(
@@ -83,15 +92,16 @@ class StreamSubscriptionError {
const stream_subscription_error = new StreamSubscriptionError();
class StreamNameError {
- report_already_exists(): void {
- $("#stream_name_error").text(
- $t({defaultMessage: "A channel with this name already exists."}),
- );
+ report_already_exists(error?: string): void {
+ const error_message =
+ error ?? $t({defaultMessage: "A channel with this name already exists."});
+ $("#stream_name_error").text(error_message);
$("#stream_name_error").show();
}
clear_errors(): void {
$("#stream_name_error").hide();
+ $("#archived_stream_rename").hide();
}
report_empty_stream(): void {
@@ -103,6 +113,12 @@ class StreamNameError {
$("#create_stream_name").trigger("focus").trigger("select");
}
+ rename_archived_stream(stream_id: number): void {
+ $("#archived_stream_rename").text($t({defaultMessage: "Rename archived channel"}));
+ $("#archived_stream_rename").attr("data-stream-id", stream_id);
+ $("#archived_stream_rename").show();
+ }
+
pre_validate(stream_name: string): void {
// Don't worry about empty strings...we just want to call this
// to warn users early before they start doing too much work
@@ -111,8 +127,16 @@ class StreamNameError {
// out it already exists, and I was just too lazy to look at
// the public streams that I'm not subscribed to yet. Once I
// realize the stream already exists, I may want to cancel.)
- if (stream_name && stream_data.get_sub(stream_name)) {
- this.report_already_exists();
+ const stream = stream_data.get_sub(stream_name);
+ if (stream_name && stream) {
+ let error;
+ if (stream.is_archived) {
+ error = $t({defaultMessage: "An archived channel with this name already exists."});
+ if (stream_settings_data.get_sub_for_settings(stream).can_change_name_description) {
+ this.rename_archived_stream(stream.stream_id);
+ }
+ }
+ this.report_already_exists(error);
return;
}
@@ -126,8 +150,13 @@ class StreamNameError {
return false;
}
- if (stream_data.get_sub(stream_name)) {
- this.report_already_exists();
+ const stream = stream_data.get_sub(stream_name);
+ if (stream) {
+ let error;
+ if (stream.is_archived) {
+ error = $t({defaultMessage: "An archived channel with this name already exists."});
+ }
+ this.report_already_exists(error);
this.select();
return false;
}
@@ -380,13 +409,19 @@ function create_stream(): void {
// "Error creating channel"?
stream_name_error.report_already_exists();
stream_name_error.select();
- }
+ const message = $t_html({
+ defaultMessage:
+ "Error creating channel: A channel with this name already exists.",
+ });
- ui_report.error(
- $t_html({defaultMessage: "Error creating channel"}),
- xhr,
- $(".stream_create_info"),
- );
+ ui_report.error(message, undefined, $(".stream_create_info"));
+ } else {
+ ui_report.error(
+ $t_html({defaultMessage: "Error creating channel"}),
+ xhr,
+ $(".stream_create_info"),
+ );
+ }
loading.destroy_indicator($("#stream_creating_indicator"));
},
});
@@ -548,3 +583,56 @@ export function set_up_handlers(): void {
assert(stream_settings_components.new_stream_can_remove_subscribers_group_widget !== null);
stream_settings_components.new_stream_can_remove_subscribers_group_widget.setup();
}
+
+export function initialize(): void {
+ $("#channels_overlay_container").on("click", "#archived_stream_rename", (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const stream_id = Number.parseInt($("#archived_stream_rename").attr("data-stream-id")!, 10);
+ const stream = stream_data.get_sub_by_id(stream_id);
+
+ assert(stream !== undefined);
+
+ const template_data = {
+ stream_name: stream.name,
+ stream_description: stream.description,
+ max_stream_name_length: realm.max_stream_name_length,
+ max_stream_description_length: realm.max_stream_description_length,
+ };
+ const change_stream_info_modal = render_change_stream_info_modal(template_data);
+ dialog_widget.launch({
+ html_heading: $t_html(
+ {defaultMessage: "Edit #{stream_name} (archived)"},
+ {stream_name: stream.name},
+ ),
+ html_body: change_stream_info_modal,
+ id: "change_stream_info_modal",
+ loading_spinner: true,
+ on_click: save_stream_info,
+ post_render() {
+ $("#change_stream_info_modal .dialog_submit_button")
+ .addClass("save-button")
+ .attr("data-stream-id", stream_id);
+ },
+ update_submit_disabled_state_on_change: true,
+ });
+ });
+
+ function save_stream_info(): void {
+ const stream_id = Number.parseInt($("#archived_stream_rename").attr("data-stream-id")!, 10);
+ const sub = stream_data.get_sub_by_id(stream_id);
+ const url = `/json/streams/${sub?.stream_id}`;
+ const data: {new_name?: string; description?: string} = {};
+ const new_name = $("#change_stream_name").val()!.trim();
+ const new_description = $("#change_stream_description").val()!.trim();
+
+ if (new_name !== sub?.name) {
+ data.new_name = new_name;
+ }
+ if (new_description !== sub?.description) {
+ data.description = new_description;
+ }
+
+ dialog_widget.submit_api_request(channel.patch, url, data);
+ }
+}
diff --git a/web/src/stream_settings_ui.js b/web/src/stream_settings_ui.js
index 39b8b3d739..1d4ff231ab 100644
--- a/web/src/stream_settings_ui.js
+++ b/web/src/stream_settings_ui.js
@@ -124,6 +124,9 @@ export function update_stream_name(sub, new_name) {
// Update navbar if needed
message_view_header.maybe_rerender_title_area_for_stream(sub);
+
+ // Update the create stream error if needed
+ stream_create.maybe_update_error_message();
}
export function update_stream_description(sub, description, rendered_description) {
diff --git a/web/src/ui_init.js b/web/src/ui_init.js
index 3a001a8b26..d14fafa093 100644
--- a/web/src/ui_init.js
+++ b/web/src/ui_init.js
@@ -117,6 +117,7 @@ import * as starred_messages from "./starred_messages";
import * as starred_messages_ui from "./starred_messages_ui";
import {current_user, realm, set_current_user, set_realm, state_data_schema} from "./state_data";
import * as stream_card_popover from "./stream_card_popover";
+import * as stream_create from "./stream_create";
import * as stream_data from "./stream_data";
import * as stream_edit from "./stream_edit";
import * as stream_edit_subscribers from "./stream_edit_subscribers";
@@ -533,6 +534,7 @@ export function initialize_everything(state_data) {
on_send_message_success: compose.send_message_success,
send_message: transmit.send_message,
});
+ stream_create.initialize();
stream_edit.initialize();
user_group_edit.initialize();
stream_edit_subscribers.initialize();
diff --git a/web/templates/stream_settings/stream_creation_form.hbs b/web/templates/stream_settings/stream_creation_form.hbs
index dba3614862..7b2bc37e3e 100644
--- a/web/templates/stream_settings/stream_creation_form.hbs
+++ b/web/templates/stream_settings/stream_creation_form.hbs
@@ -13,6 +13,7 @@
+