mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
streams: Add UI to add or remove stream from a folder.
This commit adds UI to add a stream to a folder while creating them and also for adding/removing an existing stream from a folder.
This commit is contained in:
@@ -8,8 +8,10 @@ import render_compose_banner from "../templates/compose_banner/compose_banner.hb
|
||||
|
||||
import * as blueslip from "./blueslip.ts";
|
||||
import * as buttons from "./buttons.ts";
|
||||
import * as channel_folders from "./channel_folders.ts";
|
||||
import * as compose_banner from "./compose_banner.ts";
|
||||
import type {DropdownWidget} from "./dropdown_widget.ts";
|
||||
import * as dropdown_widget from "./dropdown_widget.ts";
|
||||
import * as group_permission_settings from "./group_permission_settings.ts";
|
||||
import type {AssignedGroupPermission, GroupGroupSettingName} from "./group_permission_settings.ts";
|
||||
import * as group_setting_pill from "./group_setting_pill.ts";
|
||||
@@ -476,6 +478,7 @@ const dropdown_widget_map = new Map<string, DropdownWidget | null>([
|
||||
["realm_default_code_block_language", null],
|
||||
["realm_can_access_all_users_group", null],
|
||||
["realm_can_create_web_public_channel_group", null],
|
||||
["folder_id", null],
|
||||
]);
|
||||
|
||||
export function get_widget_for_dropdown_list_settings(
|
||||
@@ -902,6 +905,9 @@ export function check_stream_settings_property_changed(
|
||||
case "stream_privacy":
|
||||
proposed_val = get_input_element_value(elem, "radio-group");
|
||||
break;
|
||||
case "folder_id":
|
||||
proposed_val = get_channel_folder_value_from_dropdown_widget($(elem));
|
||||
break;
|
||||
default:
|
||||
if (current_val !== undefined) {
|
||||
proposed_val = get_input_element_value(elem, typeof current_val);
|
||||
@@ -1154,6 +1160,12 @@ export function populate_data_for_stream_settings_request(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property_name === "folder_id") {
|
||||
const folder_id = get_channel_folder_value_from_dropdown_widget($input_elem);
|
||||
data[property_name] = JSON.stringify(folder_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(typeof input_value !== "object");
|
||||
data[property_name] = input_value;
|
||||
}
|
||||
@@ -1940,3 +1952,79 @@ export function get_group_assigned_user_group_permissions(group: UserGroup): {
|
||||
|
||||
return group_assigned_user_group_permissions;
|
||||
}
|
||||
|
||||
export function set_up_folder_dropdown_widget(sub?: StreamSubscription): DropdownWidget {
|
||||
const folder_options = (): dropdown_widget.Option[] => {
|
||||
const folders = channel_folders.get_channel_folders();
|
||||
const options: dropdown_widget.Option[] = folders.map((folder) => ({
|
||||
name: folder.name,
|
||||
unique_id: folder.id,
|
||||
}));
|
||||
|
||||
const disabled_option = {
|
||||
is_setting_disabled: true,
|
||||
show_disabled_icon: false,
|
||||
show_disabled_option_name: true,
|
||||
unique_id: settings_config.no_folder_selected,
|
||||
name: $t({defaultMessage: "None"}),
|
||||
};
|
||||
|
||||
options.unshift(disabled_option);
|
||||
return options;
|
||||
};
|
||||
|
||||
const default_id = sub?.folder_id ?? settings_config.no_folder_selected;
|
||||
|
||||
let widget_name = "folder_id";
|
||||
if (sub === undefined) {
|
||||
widget_name = "new_channel_folder_id";
|
||||
}
|
||||
|
||||
let $events_container = $("#stream_settings .subscription_settings");
|
||||
if (sub === undefined) {
|
||||
$events_container = $("#stream_creation_form");
|
||||
}
|
||||
|
||||
const folder_widget = new dropdown_widget.DropdownWidget({
|
||||
widget_name,
|
||||
get_options: folder_options,
|
||||
$events_container,
|
||||
item_click_callback(event, dropdown, this_widget) {
|
||||
dropdown.hide();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this_widget.render();
|
||||
if (sub !== undefined) {
|
||||
const $edit_container = stream_settings_containers.get_edit_container(sub);
|
||||
save_discard_stream_settings_widget_status_handler(
|
||||
$edit_container.find(".channel-folder-subsection"),
|
||||
stream_data.get_sub_by_id(sub.stream_id),
|
||||
);
|
||||
}
|
||||
},
|
||||
default_id,
|
||||
unique_id_type: "number",
|
||||
});
|
||||
if (sub !== undefined) {
|
||||
set_dropdown_setting_widget("folder_id", folder_widget);
|
||||
}
|
||||
folder_widget.setup();
|
||||
return folder_widget;
|
||||
}
|
||||
|
||||
export function set_channel_folder_dropdown_value(sub: StreamSubscription): void {
|
||||
if (sub.folder_id === null) {
|
||||
set_dropdown_list_widget_setting_value("folder_id", settings_config.no_folder_selected);
|
||||
return;
|
||||
}
|
||||
set_dropdown_list_widget_setting_value("folder_id", sub.folder_id);
|
||||
}
|
||||
|
||||
export function get_channel_folder_value_from_dropdown_widget($elem: JQuery): number | null {
|
||||
const value = get_dropdown_list_widget_setting_value($elem);
|
||||
assert(typeof value === "number");
|
||||
if (value === settings_config.no_folder_selected) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@@ -1274,3 +1274,5 @@ export const realm_plan_types = {
|
||||
standard_free: {code: 4},
|
||||
plus: {code: 10},
|
||||
};
|
||||
|
||||
export const no_folder_selected = -1;
|
||||
|
@@ -627,6 +627,9 @@ export function discard_stream_property_element_changes(
|
||||
case "message_retention_days":
|
||||
set_message_retention_setting_dropdown(sub);
|
||||
break;
|
||||
case "folder_id":
|
||||
settings_components.set_channel_folder_dropdown_value(sub);
|
||||
break;
|
||||
default:
|
||||
if (property_value !== undefined) {
|
||||
const validated_property_value = z
|
||||
|
@@ -8,12 +8,14 @@ import render_change_stream_info_modal from "../templates/stream_settings/change
|
||||
import * as channel from "./channel.ts";
|
||||
import * as confirm_dialog from "./confirm_dialog.ts";
|
||||
import * as dialog_widget from "./dialog_widget.ts";
|
||||
import type {DropdownWidget} from "./dropdown_widget.ts";
|
||||
import {$t, $t_html} from "./i18n.ts";
|
||||
import * as keydown_util from "./keydown_util.ts";
|
||||
import * as loading from "./loading.ts";
|
||||
import * as onboarding_steps from "./onboarding_steps.ts";
|
||||
import * as resize from "./resize.ts";
|
||||
import * as settings_components from "./settings_components.ts";
|
||||
import * as settings_config from "./settings_config.ts";
|
||||
import * as settings_data from "./settings_data.ts";
|
||||
import {current_user, realm} from "./state_data.ts";
|
||||
import * as stream_create_subscribers from "./stream_create_subscribers.ts";
|
||||
@@ -32,6 +34,8 @@ let created_stream: string | undefined;
|
||||
// the subscribers list initially.
|
||||
let current_user_subscribed_to_created_stream = true;
|
||||
|
||||
let folder_widget: DropdownWidget | undefined;
|
||||
|
||||
export function reset_created_stream(): void {
|
||||
created_stream = undefined;
|
||||
}
|
||||
@@ -383,7 +387,7 @@ function create_stream(): void {
|
||||
text: $t({defaultMessage: "Creating channel..."}),
|
||||
});
|
||||
|
||||
const data = {
|
||||
const data: Record<string, string> = {
|
||||
subscriptions,
|
||||
is_web_public: JSON.stringify(is_web_public),
|
||||
invite_only: JSON.stringify(invite_only),
|
||||
@@ -395,6 +399,14 @@ function create_stream(): void {
|
||||
...group_setting_values,
|
||||
};
|
||||
|
||||
assert(folder_widget !== undefined);
|
||||
const folder_id = folder_widget.value();
|
||||
if (folder_id !== settings_config.no_folder_selected) {
|
||||
// We do not include "folder_id" in request data if
|
||||
// new stream will not be added to any folder.
|
||||
data.folder_id = JSON.stringify(folder_id);
|
||||
}
|
||||
|
||||
// Subscribe yourself and possible other people to a new stream.
|
||||
void channel.post({
|
||||
url: "/json/users/me/subscriptions",
|
||||
@@ -621,6 +633,7 @@ export function set_up_handlers(): void {
|
||||
|
||||
set_up_group_setting_widgets();
|
||||
settings_components.enable_opening_typeahead_on_clicking_label($container);
|
||||
folder_widget = settings_components.set_up_folder_dropdown_widget();
|
||||
}
|
||||
|
||||
export function initialize(): void {
|
||||
|
@@ -451,6 +451,10 @@ export function update_stream_permission_group_setting(
|
||||
sub[setting_name] = group_setting;
|
||||
}
|
||||
|
||||
export function update_channel_folder(sub: StreamSubscription, folder_id: number | null): void {
|
||||
sub.folder_id = folder_id;
|
||||
}
|
||||
|
||||
export function receives_notifications(
|
||||
stream_id: number,
|
||||
notification_name: keyof StreamSpecificNotificationSettings,
|
||||
|
@@ -291,6 +291,7 @@ export function show_settings_for(node: HTMLElement): void {
|
||||
stream_ui_updates.enable_or_disable_permission_settings_in_edit_panel(sub);
|
||||
setup_group_setting_widgets(slim_sub);
|
||||
stream_ui_updates.update_can_subscribe_group_label($edit_container);
|
||||
settings_components.set_up_folder_dropdown_widget(sub);
|
||||
|
||||
$("#channels_overlay_container").on(
|
||||
"click",
|
||||
|
@@ -214,6 +214,9 @@ export function update_property<P extends keyof UpdatableStreamProperties>(
|
||||
}
|
||||
message_live_update.rerender_messages_view();
|
||||
},
|
||||
folder_id(value) {
|
||||
stream_settings_ui.update_channel_folder(sub, value);
|
||||
},
|
||||
};
|
||||
|
||||
if (Object.hasOwn(updaters, property) && updaters[property] !== undefined) {
|
||||
|
@@ -231,6 +231,11 @@ export function update_is_default_stream(): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function update_channel_folder(sub: StreamSubscription, folder_id: number | null): void {
|
||||
stream_data.update_channel_folder(sub, folder_id);
|
||||
stream_ui_updates.update_channel_folder_dropdown(sub);
|
||||
}
|
||||
|
||||
export function update_subscribers_ui(sub: StreamSubscription): void {
|
||||
update_left_panel_row(sub);
|
||||
stream_edit_subscribers.update_subscribers_list(sub);
|
||||
|
@@ -41,6 +41,7 @@ export const stream_schema = z.object({
|
||||
can_send_message_group: group_setting_value_schema,
|
||||
can_subscribe_group: group_setting_value_schema,
|
||||
is_recently_active: z.boolean(),
|
||||
folder_id: z.number().nullable(),
|
||||
});
|
||||
|
||||
export const stream_specific_notification_settings_schema = z.object({
|
||||
|
@@ -352,6 +352,10 @@ export function enable_or_disable_permission_settings_in_edit_panel(
|
||||
.find(".input")
|
||||
.prop("contenteditable", sub.can_change_stream_permissions_requiring_metadata_access);
|
||||
|
||||
$stream_settings
|
||||
.find(".channel-folder-widget-container button")
|
||||
.prop("disabled", !sub.can_change_stream_permissions_requiring_metadata_access);
|
||||
|
||||
if (!sub.can_change_stream_permissions_requiring_metadata_access) {
|
||||
$general_settings_container.find(".default-stream").addClass("control-label-disabled");
|
||||
$permission_pill_container_elements
|
||||
@@ -607,3 +611,11 @@ export function update_stream_privacy_choices(policy: string): void {
|
||||
update_web_public_stream_privacy_option_state($container);
|
||||
}
|
||||
}
|
||||
|
||||
export function update_channel_folder_dropdown(sub: StreamSubscription): void {
|
||||
if (!hash_parser.is_editing_stream(sub.stream_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings_components.set_channel_folder_dropdown_value(sub);
|
||||
}
|
||||
|
@@ -1358,6 +1358,14 @@ div.settings-radio-input-parent {
|
||||
margin: -6px 0 -6px -10px;
|
||||
}
|
||||
|
||||
#subscription_overlay .channel-folder-widget-container {
|
||||
.dropdown_widget_value {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
#deactivation-confirm-modal {
|
||||
.alert {
|
||||
padding-right: 14px;
|
||||
|
@@ -27,7 +27,8 @@
|
||||
<div class="stream-types">
|
||||
{{> stream_types .
|
||||
is_stream_edit=false
|
||||
prefix="id_new_" }}
|
||||
prefix="id_new_"
|
||||
channel_folder_widget_name="new_channel_folder_id"}}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
@@ -87,6 +87,7 @@
|
||||
is_stream_edit=true
|
||||
prefix="id_"
|
||||
group_setting_labels=../group_setting_labels
|
||||
channel_folder_widget_name="folder_id"
|
||||
}}
|
||||
{{/with}}
|
||||
<div class="stream_details_box">
|
||||
|
@@ -43,6 +43,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="channel-folder-subsection {{#if is_stream_edit}}settings-subsection-parent{{/if}}">
|
||||
<div class="channel-folder-title-container {{#if is_stream_edit}}subsection-header{{/if}}">
|
||||
<h3 class="stream_setting_subsection_title">{{t "Folders"}}</h3>
|
||||
{{#if is_stream_edit}}
|
||||
{{> ../settings/settings_save_discard_widget section_name="stream-permissions" }}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="input-group channel-folder-container">
|
||||
<label class="settings-field-label" for="{{channel_folder_widget_name}}_widget">
|
||||
{{t "Channel folder"}}
|
||||
</label>
|
||||
<span class="prop-element hide" id="id_{{channel_folder_widget_name}}" data-setting-widget-type="dropdown-list-widget" data-setting-value-type="number"></span>
|
||||
<div class="dropdown_widget_with_label_wrapper channel-folder-widget-container">
|
||||
{{> ../dropdown_widget widget_name=channel_folder_widget_name}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="advanced-configurations-container {{#if is_stream_edit}}settings-subsection-parent{{/if}}">
|
||||
<div class="advance-config-title-container {{#if is_stream_edit}}subsection-header{{/if}}">
|
||||
<div class="advance-config-toggle-area">
|
||||
|
@@ -839,11 +839,13 @@ test("stream_settings", ({override}) => {
|
||||
sub,
|
||||
moderators_group.id,
|
||||
);
|
||||
stream_data.update_channel_folder(sub, 3);
|
||||
assert.equal(sub.invite_only, false);
|
||||
assert.equal(sub.history_public_to_subscribers, false);
|
||||
assert.equal(sub.message_retention_days, -1);
|
||||
assert.equal(sub.can_remove_subscribers_group, moderators_group.id);
|
||||
assert.equal(sub.can_administer_channel_group, moderators_group.id);
|
||||
assert.equal(sub.folder_id, 3);
|
||||
|
||||
// For guest user only retrieve subscribed streams
|
||||
sub_rows = stream_settings_data.get_updated_unsorted_subs();
|
||||
|
@@ -327,6 +327,17 @@ test("update_property", ({override}) => {
|
||||
assert.equal(args.sub, sub);
|
||||
}
|
||||
|
||||
// Update channel folder
|
||||
{
|
||||
const stub = make_stub();
|
||||
override(stream_settings_ui, "update_channel_folder", stub.f);
|
||||
stream_events.update_property(stream_id, "folder_id", 3);
|
||||
assert.equal(stub.num_calls, 1);
|
||||
const args = stub.get_args("sub", "value");
|
||||
assert.equal(args.sub.stream_id, stream_id);
|
||||
assert.equal(args.value, 3);
|
||||
}
|
||||
|
||||
// Test archiving stream
|
||||
{
|
||||
stream_data.subscribe_myself(sub);
|
||||
|
Reference in New Issue
Block a user