mirror of https://github.com/zulip/zulip.git
user groups: Add new UI support for user group creation.
Add support for creation of user groups using right panel of new user group settings overlay being developed as part of https://github.com/zulip/zulip/issues/19526. In further commits we will add support for editing user groups using right panel of the overlay. This commit also introduces a minor bug related hashchange for #groups which would be a quick fix once we have UI for group edit on #groups overlay.
This commit is contained in:
parent
c1cb5a6ef1
commit
a8c3be7fee
|
@ -99,6 +99,7 @@ import * as ui from "./ui";
|
||||||
import * as unread from "./unread";
|
import * as unread from "./unread";
|
||||||
import * as unread_ui from "./unread_ui";
|
import * as unread_ui from "./unread_ui";
|
||||||
import * as user_groups from "./user_groups";
|
import * as user_groups from "./user_groups";
|
||||||
|
import * as user_group_settings_ui from "./user_groups_settings_ui";
|
||||||
import {initialize_user_settings, user_settings} from "./user_settings";
|
import {initialize_user_settings, user_settings} from "./user_settings";
|
||||||
import * as user_status from "./user_status";
|
import * as user_status from "./user_status";
|
||||||
import * as user_status_ui from "./user_status_ui";
|
import * as user_status_ui from "./user_status_ui";
|
||||||
|
@ -623,6 +624,7 @@ export function initialize_everything() {
|
||||||
user_topics.initialize();
|
user_topics.initialize();
|
||||||
muted_users.initialize();
|
muted_users.initialize();
|
||||||
stream_settings_ui.initialize();
|
stream_settings_ui.initialize();
|
||||||
|
user_group_settings_ui.initialize();
|
||||||
stream_list.initialize();
|
stream_list.initialize();
|
||||||
condense.initialize();
|
condense.initialize();
|
||||||
spoilers.initialize();
|
spoilers.initialize();
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
|
import * as channel from "./channel";
|
||||||
|
import {$t, $t_html} from "./i18n";
|
||||||
|
import * as loading from "./loading";
|
||||||
|
import * as ui_report from "./ui_report";
|
||||||
|
import * as user_group_create_members from "./user_group_create_members";
|
||||||
|
import * as user_group_create_members_data from "./user_group_create_members_data";
|
||||||
|
import * as user_groups from "./user_groups";
|
||||||
|
import * as user_group_settings_ui from "./user_groups_settings_ui";
|
||||||
|
|
||||||
|
class UserGroupMembershipError {
|
||||||
|
report_no_members_to_user_group() {
|
||||||
|
$("#user_group_membership_error").text(
|
||||||
|
$t({defaultMessage: "You cannot create a user_group with no members!"}),
|
||||||
|
);
|
||||||
|
$("#user_group_membership_error").show();
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_errors() {
|
||||||
|
$("#user_group_membership_error").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const user_group_membership_error = new UserGroupMembershipError();
|
||||||
|
|
||||||
|
class UserGroupNameError {
|
||||||
|
report_already_exists() {
|
||||||
|
$("#user_group_name_error").text(
|
||||||
|
$t({defaultMessage: "A user group with this name already exists"}),
|
||||||
|
);
|
||||||
|
$("#user_group_name_error").show();
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_errors() {
|
||||||
|
$("#user_group_name_error").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
report_empty_user_group() {
|
||||||
|
$("#user_group_name_error").text($t({defaultMessage: "A user group needs to have a name"}));
|
||||||
|
$("#user_group_name_error").show();
|
||||||
|
}
|
||||||
|
|
||||||
|
select() {
|
||||||
|
$("#create_user_group_name").trigger("focus").trigger("select");
|
||||||
|
}
|
||||||
|
|
||||||
|
pre_validate(user_group_name) {
|
||||||
|
if (user_group_name && user_groups.get_user_group_from_name(user_group_name)) {
|
||||||
|
this.report_already_exists();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clear_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_for_submit(user_group_name) {
|
||||||
|
if (!user_group_name) {
|
||||||
|
this.report_empty_user_group();
|
||||||
|
this.select();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_groups.get_user_group_from_name(user_group_name)) {
|
||||||
|
this.report_already_exists();
|
||||||
|
this.select();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const user_group_name_error = new UserGroupNameError();
|
||||||
|
|
||||||
|
export function create_user_group_clicked() {
|
||||||
|
// this changes the tab switcher (settings/preview) which isn't necessary
|
||||||
|
// to a add new stream title.
|
||||||
|
user_group_settings_ui.show_user_group_settings_pane.create_user_group();
|
||||||
|
$(".group-row.active").removeClass("active");
|
||||||
|
|
||||||
|
show_new_user_group_modal();
|
||||||
|
$("#create_user_group_name").trigger("focus");
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear_error_display() {
|
||||||
|
user_group_name_error.clear_errors();
|
||||||
|
$(".user_group_create_info").hide();
|
||||||
|
user_group_membership_error.clear_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function show_new_user_group_modal() {
|
||||||
|
$("#user-group-creation").removeClass("hide");
|
||||||
|
$(".right .settings").hide();
|
||||||
|
|
||||||
|
user_group_create_members.build_widgets();
|
||||||
|
|
||||||
|
clear_error_display();
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_user_group() {
|
||||||
|
const data = {};
|
||||||
|
const group_name = $("#create_user_group_name").val().trim();
|
||||||
|
const description = $("#create_user_group_description").val().trim();
|
||||||
|
|
||||||
|
// Even though we already check to make sure that while typing the user cannot enter
|
||||||
|
// newline characters (by pressing the Enter key) it would still be possible to copy
|
||||||
|
// and paste over a description with newline characters in it. Prevent that.
|
||||||
|
if (description.includes("\n")) {
|
||||||
|
ui_report.client_error(
|
||||||
|
$t_html({defaultMessage: "The group description cannot contain newline characters."}),
|
||||||
|
$(".user_group_create_info"),
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
data.name = group_name;
|
||||||
|
data.description = description;
|
||||||
|
|
||||||
|
const user_ids = user_group_create_members.get_principals();
|
||||||
|
data.members = JSON.stringify(user_ids);
|
||||||
|
|
||||||
|
loading.make_indicator($("#user_group_creating_indicator"), {
|
||||||
|
text: $t({defaultMessage: "Creating group..."}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return channel.post({
|
||||||
|
url: "/json/user_groups/create",
|
||||||
|
data,
|
||||||
|
success() {
|
||||||
|
$("#create_user_group_name").val("");
|
||||||
|
$("#create_user_group_description").val("");
|
||||||
|
user_group_create_members.clear_member_list();
|
||||||
|
ui_report.success(
|
||||||
|
$t_html({defaultMessage: "User group successfully created!"}),
|
||||||
|
$(".user_group_create_info"),
|
||||||
|
);
|
||||||
|
loading.destroy_indicator($("#user_group_creating_indicator"));
|
||||||
|
// TODO: The rest of the work should be done via the create event we will get for user group.
|
||||||
|
},
|
||||||
|
error(xhr) {
|
||||||
|
ui_report.error(
|
||||||
|
$t_html({defaultMessage: "Error creating user group."}),
|
||||||
|
xhr,
|
||||||
|
$(".user_group_create_info"),
|
||||||
|
);
|
||||||
|
loading.destroy_indicator($("#user_group_creating_indicator"));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function set_up_handlers() {
|
||||||
|
const $people_to_add_holder = $("#people_to_add_in_group").expectOne();
|
||||||
|
user_group_create_members.create_handlers($people_to_add_holder);
|
||||||
|
|
||||||
|
const $container = $("#user-group-creation").expectOne();
|
||||||
|
|
||||||
|
$container.on("click", ".finalize_create_user_group", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
clear_error_display();
|
||||||
|
|
||||||
|
const group_name = $("#create_user_group_name").val().trim();
|
||||||
|
const name_ok = user_group_name_error.validate_for_submit(group_name);
|
||||||
|
|
||||||
|
if (!name_ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const principals = user_group_create_members_data.get_principals();
|
||||||
|
if (principals.length === 0) {
|
||||||
|
user_group_membership_error.report_no_members_to_user_group();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_user_group();
|
||||||
|
});
|
||||||
|
|
||||||
|
$container.on("input", "#create_user_group_name", () => {
|
||||||
|
const user_group_name = $("#create_user_group_name").val().trim();
|
||||||
|
|
||||||
|
// This is an inexpensive check.
|
||||||
|
user_group_name_error.pre_validate(user_group_name);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Do not allow the user to enter newline characters while typing out the
|
||||||
|
// group's description during it's creation.
|
||||||
|
$container.on("keydown", "#create_user_group_description", (e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
|
import render_new_user_group_user from "../templates/stream_settings/new_stream_user.hbs";
|
||||||
|
import render_new_user_group_users from "../templates/user_group_settings/new_user_group_users.hbs";
|
||||||
|
|
||||||
|
import * as add_subscribers_pill from "./add_subscribers_pill";
|
||||||
|
import * as ListWidget from "./list_widget";
|
||||||
|
import {page_params} from "./page_params";
|
||||||
|
import * as people from "./people";
|
||||||
|
import * as settings_data from "./settings_data";
|
||||||
|
import * as user_group_create_members_data from "./user_group_create_members_data";
|
||||||
|
|
||||||
|
let pill_widget;
|
||||||
|
let all_users_list_widget;
|
||||||
|
|
||||||
|
export function get_principals() {
|
||||||
|
return user_group_create_members_data.get_principals();
|
||||||
|
}
|
||||||
|
|
||||||
|
function redraw_member_list() {
|
||||||
|
all_users_list_widget.replace_list_data(user_group_create_members_data.sorted_user_ids());
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_user_ids(user_ids) {
|
||||||
|
user_group_create_members_data.add_user_ids(user_ids);
|
||||||
|
redraw_member_list();
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_all_users() {
|
||||||
|
const user_ids = user_group_create_members_data.get_all_user_ids();
|
||||||
|
add_user_ids(user_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove_user_ids(user_ids) {
|
||||||
|
user_group_create_members_data.remove_user_ids(user_ids);
|
||||||
|
redraw_member_list();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clear_member_list() {
|
||||||
|
user_group_create_members_data.initialize_with_current_user();
|
||||||
|
redraw_member_list();
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_pill_widget({$parent_container}) {
|
||||||
|
const $pill_container = $parent_container.find(".pill-container");
|
||||||
|
const get_potential_members = user_group_create_members_data.get_potential_members;
|
||||||
|
|
||||||
|
pill_widget = add_subscribers_pill.create({
|
||||||
|
$pill_container,
|
||||||
|
get_potential_subscribers: get_potential_members,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function create_handlers($container) {
|
||||||
|
$container.on("click", ".add_all_users_to_user_group", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
add_all_users();
|
||||||
|
$(".add-user-list-filter").trigger("focus");
|
||||||
|
});
|
||||||
|
|
||||||
|
$container.on("click", ".remove_potential_subscriber", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const $elem = $(e.target);
|
||||||
|
const user_id = Number.parseInt($elem.attr("data-user-id"), 10);
|
||||||
|
remove_user_ids([user_id]);
|
||||||
|
});
|
||||||
|
|
||||||
|
function add_users({pill_user_ids}) {
|
||||||
|
add_user_ids(pill_user_ids);
|
||||||
|
pill_widget.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
add_subscribers_pill.set_up_handlers({
|
||||||
|
get_pill_widget: () => pill_widget,
|
||||||
|
$parent_container: $container,
|
||||||
|
pill_selector: ".add_subscribers_container .input",
|
||||||
|
button_selector: ".add_subscribers_container button.add-subscriber-button",
|
||||||
|
action: add_users,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function build_widgets() {
|
||||||
|
const $add_people_container = $("#people_to_add_in_group");
|
||||||
|
$add_people_container.html(render_new_user_group_users({}));
|
||||||
|
|
||||||
|
const $simplebar_container = $add_people_container.find(".member_list_container");
|
||||||
|
|
||||||
|
build_pill_widget({$parent_container: $add_people_container});
|
||||||
|
|
||||||
|
user_group_create_members_data.initialize_with_current_user();
|
||||||
|
const current_user_id = page_params.user_id;
|
||||||
|
|
||||||
|
all_users_list_widget = ListWidget.create($("#create_user_group_members"), [current_user_id], {
|
||||||
|
name: "new_user_group_add_users",
|
||||||
|
$parent_container: $add_people_container,
|
||||||
|
modifier(user_id) {
|
||||||
|
const user = people.get_by_user_id(user_id);
|
||||||
|
const item = {
|
||||||
|
show_email: settings_data.show_email(),
|
||||||
|
email: people.get_visible_email(user),
|
||||||
|
user_id,
|
||||||
|
full_name: user.full_name,
|
||||||
|
is_current_user: user_id === current_user_id,
|
||||||
|
disabled: user_id === current_user_id,
|
||||||
|
};
|
||||||
|
return render_new_user_group_user(item);
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
$element: $("#people_to_add_in_group .add-user-list-filter"),
|
||||||
|
predicate(user_id, search_term) {
|
||||||
|
const user = people.get_by_user_id(user_id);
|
||||||
|
return people.build_person_matcher(search_term)(user);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
$simplebar_container,
|
||||||
|
html_selector: (user_id) => {
|
||||||
|
const user = people.get_by_user_id(user_id);
|
||||||
|
return $(`#${CSS.escape("user_checkbox_" + user.user_id)}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
import {page_params} from "./page_params";
|
||||||
|
import * as people from "./people";
|
||||||
|
|
||||||
|
let user_id_set;
|
||||||
|
|
||||||
|
export function initialize_with_current_user() {
|
||||||
|
const current_user_id = page_params.user_id;
|
||||||
|
user_id_set = new Set();
|
||||||
|
user_id_set.add(current_user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sorted_user_ids() {
|
||||||
|
const users = people.get_users_from_ids(Array.from(user_id_set));
|
||||||
|
people.sort_but_pin_current_user_on_top(users);
|
||||||
|
return users.map((user) => user.user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_all_user_ids() {
|
||||||
|
const potential_members = people.get_realm_users();
|
||||||
|
const user_ids = potential_members.map((user) => user.user_id);
|
||||||
|
// sort for determinism
|
||||||
|
user_ids.sort((a, b) => a - b);
|
||||||
|
return user_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_principals() {
|
||||||
|
// Return list of user ids which were selected by user.
|
||||||
|
return Array.from(user_id_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_potential_members() {
|
||||||
|
const potential_members = people.get_realm_users();
|
||||||
|
return potential_members.filter((user) => !user_id_set.has(user.user_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function add_user_ids(user_ids) {
|
||||||
|
for (const user_id of user_ids) {
|
||||||
|
if (!user_id_set.has(user_id)) {
|
||||||
|
const user = people.get_by_user_id(user_id);
|
||||||
|
if (user) {
|
||||||
|
user_id_set.add(user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function remove_user_ids(user_ids) {
|
||||||
|
for (const user_id of user_ids) {
|
||||||
|
user_id_set.delete(user_id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,13 @@ import render_browse_user_groups_list_item from "../templates/user_group_setting
|
||||||
import render_user_group_settings_overlay from "../templates/user_group_settings/user_group_settings_overlay.hbs";
|
import render_user_group_settings_overlay from "../templates/user_group_settings/user_group_settings_overlay.hbs";
|
||||||
|
|
||||||
import * as browser_history from "./browser_history";
|
import * as browser_history from "./browser_history";
|
||||||
|
import {$t} from "./i18n";
|
||||||
import * as ListWidget from "./list_widget";
|
import * as ListWidget from "./list_widget";
|
||||||
import * as overlays from "./overlays";
|
import * as overlays from "./overlays";
|
||||||
import * as people from "./people";
|
import * as people from "./people";
|
||||||
import * as settings_data from "./settings_data";
|
import * as settings_data from "./settings_data";
|
||||||
import * as ui from "./ui";
|
import * as ui from "./ui";
|
||||||
|
import * as user_group_create from "./user_group_create";
|
||||||
import * as user_groups from "./user_groups";
|
import * as user_groups from "./user_groups";
|
||||||
|
|
||||||
export function set_up_click_handlers() {
|
export function set_up_click_handlers() {
|
||||||
|
@ -25,6 +27,26 @@ export function set_up_click_handlers() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const show_user_group_settings_pane = {
|
||||||
|
nothing_selected() {
|
||||||
|
$(".settings, #user-group-creation").hide();
|
||||||
|
$(".nothing-selected").show();
|
||||||
|
$("#groups_overlay .user-group-info-title").text(
|
||||||
|
$t({defaultMessage: "User group settings"}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
create_user_group() {
|
||||||
|
$(".nothing-selected, .settings, #user-group-creation").hide();
|
||||||
|
$("#user-group-creation").show();
|
||||||
|
$("#groups_overlay .user-group-info-title").text($t({defaultMessage: "Create user group"}));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function open_create_user_group() {
|
||||||
|
user_group_create.create_user_group_clicked();
|
||||||
|
browser_history.update("#groups/new");
|
||||||
|
}
|
||||||
|
|
||||||
export function setup_page(callback) {
|
export function setup_page(callback) {
|
||||||
function populate_and_fill() {
|
function populate_and_fill() {
|
||||||
const template_data = {
|
const template_data = {
|
||||||
|
@ -63,6 +85,7 @@ export function setup_page(callback) {
|
||||||
});
|
});
|
||||||
|
|
||||||
set_up_click_handlers();
|
set_up_click_handlers();
|
||||||
|
user_group_create.set_up_handlers();
|
||||||
|
|
||||||
// show the "User group settings" header by default.
|
// show the "User group settings" header by default.
|
||||||
$(".display-type #user_group_settings_title").show();
|
$(".display-type #user_group_settings_title").show();
|
||||||
|
@ -75,6 +98,13 @@ export function setup_page(callback) {
|
||||||
populate_and_fill();
|
populate_and_fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initialize() {
|
||||||
|
$("#manage_groups_container").on("click", ".create_user_group_button", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
open_create_user_group();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function launch() {
|
export function launch() {
|
||||||
setup_page(() => {
|
setup_page(() => {
|
||||||
overlays.open_overlay({
|
overlays.open_overlay({
|
||||||
|
|
|
@ -424,6 +424,10 @@ body.dark-theme {
|
||||||
#stream-creation
|
#stream-creation
|
||||||
#stream_creation_form
|
#stream_creation_form
|
||||||
#stream_creating_indicator:not(:empty),
|
#stream_creating_indicator:not(:empty),
|
||||||
|
#groups_overlay
|
||||||
|
#user-group-creation
|
||||||
|
#user_group_creation_form
|
||||||
|
#user_group_creating_indicator:not(:empty),
|
||||||
.emoji-info-popover
|
.emoji-info-popover
|
||||||
.emoji-popover
|
.emoji-popover
|
||||||
.emoji-popover-emoji:not(.reacted):focus {
|
.emoji-popover-emoji:not(.reacted):focus {
|
||||||
|
@ -663,6 +667,8 @@ body.dark-theme {
|
||||||
.user-groups-container .left,
|
.user-groups-container .left,
|
||||||
.subscriber-list-box,
|
.subscriber-list-box,
|
||||||
.subscriber-list-box .subscriber_list_container .subscriber-list tr,
|
.subscriber-list-box .subscriber_list_container .subscriber-list tr,
|
||||||
|
.member-list-box,
|
||||||
|
.member-list-box .member_list_container .member-list tr,
|
||||||
#subscription_overlay .subsection-parent div,
|
#subscription_overlay .subsection-parent div,
|
||||||
#subscription_overlay .radio-input-parent,
|
#subscription_overlay .radio-input-parent,
|
||||||
#stream_privacy_modal .radio-input-parent,
|
#stream_privacy_modal .radio-input-parent,
|
||||||
|
|
|
@ -96,10 +96,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#create_user_group_description,
|
||||||
#create_stream_description {
|
#create_stream_description {
|
||||||
width: calc(100% - 15px);
|
width: calc(100% - 15px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user_group_creation_error,
|
||||||
.stream_creation_error {
|
.stream_creation_error {
|
||||||
display: none;
|
display: none;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
|
@ -107,26 +109,30 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Unify with settings.css definition */
|
/* TODO: Unify with settings.css definition */
|
||||||
h3.stream_setting_subsection_title {
|
h3.stream_setting_subsection_title,
|
||||||
|
h3.user_group_setting_subsection_title {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4.stream_setting_subsection_title {
|
h4.stream_setting_subsection_title,
|
||||||
|
h4.user_group_setting_subsection_title {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1.35em;
|
font-size: 1.35em;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.member-list-box,
|
||||||
.subscriber-list-box {
|
.subscriber-list-box {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-left: 1px solid hsl(0, 0%, 87%);
|
border-left: 1px solid hsl(0, 0%, 87%);
|
||||||
border-right: 1px solid hsl(0, 0%, 87%);
|
border-right: 1px solid hsl(0, 0%, 87%);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.member_list_container,
|
||||||
.subscriber_list_container {
|
.subscriber_list_container {
|
||||||
position: relative;
|
position: relative;
|
||||||
/* 2*45px (settings header) + 38px(tab-container row) + 20px (margin for .inner-box) + 134px (add user input and search widget area) = 282px */
|
/* 2*45px (settings header) + 38px(tab-container row) + 20px (margin for .inner-box) + 134px (add user input and search widget area) = 282px */
|
||||||
|
@ -135,6 +141,7 @@ h4.stream_setting_subsection_title {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
|
||||||
|
.member-list,
|
||||||
.subscriber-list {
|
.subscriber-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
@ -206,7 +213,8 @@ h4.stream_setting_subsection_title {
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscriber_list_add {
|
.subscriber_list_add,
|
||||||
|
.member_list_add {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 0 10px;
|
margin: 0 0 10px;
|
||||||
|
|
||||||
|
@ -225,7 +233,8 @@ h4.stream_setting_subsection_title {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscriber_list_add .form-inline {
|
.subscriber_list_add .form-inline,
|
||||||
|
.member_list_add .form-inline {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,6 +494,7 @@ h4.stream_setting_subsection_title {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-group-creation-body,
|
||||||
.stream-creation-body {
|
.stream-creation-body {
|
||||||
section.block {
|
section.block {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
@ -661,7 +671,9 @@ h4.stream_setting_subsection_title {
|
||||||
color: hsl(0, 0%, 67%);
|
color: hsl(0, 0%, 67%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#groups_overlay,
|
||||||
#subscription_overlay {
|
#subscription_overlay {
|
||||||
|
#user-group-creation,
|
||||||
#stream-creation {
|
#stream-creation {
|
||||||
max-height: calc(100% - 102px);
|
max-height: calc(100% - 102px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -675,14 +687,17 @@ h4.stream_setting_subsection_title {
|
||||||
padding-top: 9px;
|
padding-top: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-group-creation-body,
|
||||||
.stream-creation-body {
|
.stream-creation-body {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.add_all_users_to_user_group,
|
||||||
.add_all_users_to_stream {
|
.add_all_users_to_stream {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.create_user_group_member_list_header,
|
||||||
.create_stream_subscriber_list_header {
|
.create_stream_subscriber_list_header {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
|
@ -697,9 +712,11 @@ h4.stream_setting_subsection_title {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#user_group_creation_form,
|
||||||
#stream_creation_form {
|
#stream_creation_form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
|
#user_group_creating_indicator,
|
||||||
#stream_creating_indicator {
|
#stream_creating_indicator {
|
||||||
&:not(:empty) {
|
&:not(:empty) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<div class="member_list_add float-left">
|
||||||
|
{{> ../stream_settings/add_subscribers_form}}
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
{{t "Do you want to add everyone?"}}
|
||||||
|
<button class="add_all_users_to_user_group small button rounded sea-green">{{t 'Add all users'}}</button>
|
||||||
|
|
||||||
|
<div class="create_member_list_header">
|
||||||
|
<h4 class="user_group_setting_subsection_title">{{t 'Members' }}</h4>
|
||||||
|
<input class="add-user-list-filter" name="user_list_filter" type="text"
|
||||||
|
autocomplete="off" placeholder="{{t 'Filter members' }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="member-list-box">
|
||||||
|
<div class="member_list_container" data-simplebar>
|
||||||
|
<table class="member-list table table-striped">
|
||||||
|
<thead class="table-sticky-headers">
|
||||||
|
<th>{{t "Name" }}</th>
|
||||||
|
<th>{{t "Email" }}</th>
|
||||||
|
<th>{{t "User ID" }}</th>
|
||||||
|
<th>{{t "Action" }}</th>
|
||||||
|
</thead>
|
||||||
|
<tbody id="create_user_group_members" class="member_table"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,35 @@
|
||||||
|
<div class="hide" id="user-group-creation" tabindex="-1" role="dialog"
|
||||||
|
aria-label="{{t 'User group creation' }}">
|
||||||
|
<form id="user_group_creation_form">
|
||||||
|
<div class="alert user_group_create_info"></div>
|
||||||
|
<div id="user_group_creating_indicator"></div>
|
||||||
|
<div class="user-group-creation-body">
|
||||||
|
<section class="block">
|
||||||
|
<label for="create_user_group_name">
|
||||||
|
{{t "User group name" }}
|
||||||
|
</label>
|
||||||
|
<input type="text" name="user_group_name" id="create_user_group_name"
|
||||||
|
placeholder="{{t 'User group name' }}" value="" autocomplete="off" />
|
||||||
|
<div id="user_group_name_error" class="user_group_creation_error"></div>
|
||||||
|
</section>
|
||||||
|
<section class="block">
|
||||||
|
<label for="create_user_group_description">
|
||||||
|
{{t "User group description" }}
|
||||||
|
</label>
|
||||||
|
<input type="text" name="user_group_description" id="create_user_group_description"
|
||||||
|
placeholder="{{t 'User group description' }}" value="" autocomplete="off" />
|
||||||
|
</section>
|
||||||
|
<section class="block">
|
||||||
|
<label for="people_to_add_in_group">
|
||||||
|
<h4 class="user_group_setting_subsection_title">{{t "Choose members" }}</h4>
|
||||||
|
</label>
|
||||||
|
<div id="user_group_membership_error" class="user_group_creation_error"></div>
|
||||||
|
<div class="controls" id="people_to_add_in_group"></div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="button small white rounded" data-dismiss="modal">{{t "Cancel" }}</button>
|
||||||
|
<button class="finalize_create_user_group button small sea-green rounded" type="submit">{{t "Create" }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -37,6 +37,7 @@
|
||||||
<div id="user_group_settings" class="settings" data-simplebar data-simplebar-auto-hide="false">
|
<div id="user_group_settings" class="settings" data-simplebar data-simplebar-auto-hide="false">
|
||||||
{{!-- edit user group here --}}
|
{{!-- edit user group here --}}
|
||||||
</div>
|
</div>
|
||||||
|
{{> user_group_creation_form }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -200,6 +200,9 @@ EXEMPT_FILES = make_set(
|
||||||
"static/js/unread_ops.js",
|
"static/js/unread_ops.js",
|
||||||
"static/js/unread_ui.js",
|
"static/js/unread_ui.js",
|
||||||
"static/js/upload_widget.ts",
|
"static/js/upload_widget.ts",
|
||||||
|
"static/js/user_group_create.js",
|
||||||
|
"static/js/user_group_create_members.js",
|
||||||
|
"static/js/user_group_create_members_data.js",
|
||||||
"static/js/user_groups_settings_ui.js",
|
"static/js/user_groups_settings_ui.js",
|
||||||
"static/js/user_profile.js",
|
"static/js/user_profile.js",
|
||||||
"static/js/user_settings.ts",
|
"static/js/user_settings.ts",
|
||||||
|
|
Loading…
Reference in New Issue