From d43b72fbc215340373ad390b331180e5bdc587ab Mon Sep 17 00:00:00 2001 From: David Wheatley Date: Sun, 1 Aug 2021 17:19:40 +0100 Subject: [PATCH] Add ability to create new user from Users List page --- js/src/admin/components/CreateUserModal.tsx | 185 ++++++++++++++++++++ js/src/admin/components/UserListPage.tsx | 15 ++ less/admin.less | 1 + less/admin/CreateUserModal.less | 6 + locale/core.yml | 43 +++-- 5 files changed, 236 insertions(+), 14 deletions(-) create mode 100644 js/src/admin/components/CreateUserModal.tsx create mode 100644 less/admin/CreateUserModal.less diff --git a/js/src/admin/components/CreateUserModal.tsx b/js/src/admin/components/CreateUserModal.tsx new file mode 100644 index 0000000000..242b7be87e --- /dev/null +++ b/js/src/admin/components/CreateUserModal.tsx @@ -0,0 +1,185 @@ +import app from '../../admin/app'; +import type Mithril from 'mithril'; +import type { ComponentAttrs } from '../../common/Component'; +import Button from '../../common/components/Button'; +import Modal from '../../common/components/Modal'; +import Switch from '../../common/components/Switch'; +import ItemList from '../../common/utils/ItemList'; +import type User from '../../common/models/User'; +import EditUserModal from '../../common/components/EditUserModal'; + +interface ICreateUserModalState { + username: string; + email: string; + isEmailConfirmed: boolean; + password: string; + showEditModalAfterClose: boolean; +} + +/** + * A Modal that allows admins to create a new user. + */ +export default class CreateUserModal extends Modal { + state: ICreateUserModalState = { + username: '', + email: '', + isEmailConfirmed: false, + password: '', + showEditModalAfterClose: true, + }; + + oninit(vnode: Mithril.Vnode) { + super.oninit(vnode); + } + + className() { + return 'CreateUserModal'; + } + + title() { + return app.translator.trans('core.admin.create_user.title'); + } + + content() { + const fields = this.fields().toArray(); + + console.log(this.state); + + return
{fields}
; + } + + fields() { + const items = new ItemList(); + + items.add( + 'username', +
+ +
, + 100 + ); + + items.add( + 'password', +
+ +
, + 80 + ); + + items.add( + 'email', + [ +
+ +
, +
+ (this.state.isEmailConfirmed = val)}> + {app.translator.trans('core.admin.create_user.email.confirmed')} + +
, + ], + 60 + ); + + items.add( + 'openEditAfterClose', + [ +
+ +
, + ], + 0 + ); + + items.add( + 'submit', +
+ +
, + -10 + ); + + return items; + } + + private twoWayLinkAttrs(key: keyof typeof this.state, valueName: string = 'value', eventName: string = 'oninput') { + return { + [valueName]: this.state[key], + [eventName]: (e: Event) => { + (this.state[key] as ICreateUserModalState[keyof ICreateUserModalState]) = (e!.currentTarget as HTMLInputElement).value; + }, + }; + } + + isDataValid(): boolean { + const { username } = this.state; + + if (!username) return false; + + return true; + } + + submitData(): { data: { attributes: Omit } } { + const { showEditModalAfterClose, ...data } = this.state; + + return { data: { attributes: data } }; + } + + onsubmit(e: SubmitEvent) { + e.preventDefault(); + + this.loading = true; + + const body = this.submitData(); + + app + .request({ + url: `${app.forum.attribute('apiUrl')}/users`, + method: 'POST', + body, + errorHandler: this.onerror.bind(this), + }) + .then((response) => { + this.hide(); + console.log(response); + + const user: User = app.store.pushPayload(response); + + // Add the missing groups relationship we can't include from the CreateUserController + user.pushData({ + relationships: { + groups: { + data: [], + }, + }, + }); + + if (this.state.showEditModalAfterClose) { + app.modal.show(EditUserModal, { user }); + } + }) + .catch((e) => { + this.loaded.call(this); + this.onerror(e); + }); + } +} diff --git a/js/src/admin/components/UserListPage.tsx b/js/src/admin/components/UserListPage.tsx index d4e05287d1..95a5c00829 100644 --- a/js/src/admin/components/UserListPage.tsx +++ b/js/src/admin/components/UserListPage.tsx @@ -16,6 +16,7 @@ import extractText from '../../common/utils/extractText'; import AdminPage from './AdminPage'; import Checkbox from '../../common/components/Checkbox'; +import CreateUserModal from './CreateUserModal'; type ColumnData = { /** @@ -190,6 +191,20 @@ export default class UserListPage extends AdminPage { 900 ); + items.add( + 'createUser', + , + 800 + ); + return items; } diff --git a/less/admin.less b/less/admin.less index 07f528fc0d..855918cd1a 100644 --- a/less/admin.less +++ b/less/admin.less @@ -12,3 +12,4 @@ @import "admin/MailPage"; @import "admin/NoJs"; @import "admin/UsersListPage.less"; +@import "admin/CreateUserModal.less"; diff --git a/less/admin/CreateUserModal.less b/less/admin/CreateUserModal.less new file mode 100644 index 0000000000..f865d52510 --- /dev/null +++ b/less/admin/CreateUserModal.less @@ -0,0 +1,6 @@ +.CreateUserModal { + label input { + margin-top: 2px; + font-weight: normal; + } +} diff --git a/locale/core.yml b/locale/core.yml index 6c662f478d..553b469490 100644 --- a/locale/core.yml +++ b/locale/core.yml @@ -1,12 +1,10 @@ core: - ## # UNIQUE KEYS - The following keys are used in only one location each. ## # Translations in this namespace are used by the admin interface. admin: - # These translations are used in the Appearance page. appearance: colored_header_label: Colored Header @@ -49,6 +47,23 @@ core: welcome_banner_heading: Welcome Banner welcome_banner_text: Configure the text that displays in the banner on the All Discussions page. Use this to welcome guests to your forum. + # These translations are used in the Create User modal. + create_user: + title: Create new user + submit_button: => core.ref.save_changes + + email: + label: => core.ref.email + confirmed: Email confirmed? + + launch_edit_after_close: Open edit user modal after creating this user? + + password: + label: => core.ref.password + + username: + label: => core.ref.username + # These translations are used in the Dashboard page. dashboard: clear_cache_button: Clear Cache @@ -262,6 +277,9 @@ core: button: Copy link to page {pageNumber} copied: => core.ref.copied + create_user: + button: Create new user + pagination: back_button: Previous page first_button: First page @@ -276,7 +294,6 @@ core: # Translations in this namespace are used by the forum user interface. forum: - # These translations are used in the Change Email modal dialog. change_email: confirm_password_placeholder: => core.ref.confirm_password @@ -507,7 +524,6 @@ core: # Translations in this namespace are used by the forum and admin interfaces. lib: - # These translations are displayed as tooltips for discussion badges. badge: hidden_tooltip: Hidden @@ -628,7 +644,6 @@ core: # Translations in this namespace are used in emails sent by the forum. email: - # These translations are used in emails sent when users register new accounts. activate_account: subject: Activate Your New Account @@ -689,7 +704,7 @@ core: all_discussions: All Discussions change_email: Change Email change_password: Change Password - color: Color # Referenced by flarum-tags.yml + color: Color # Referenced by flarum-tags.yml confirm_password: Confirm Password confirm_email: Confirm Email confirmation_email_sent: "We've sent a confirmation email to {email}. If it doesn't arrive soon, check your spam folder." @@ -700,7 +715,7 @@ core: custom_header_title: Edit Custom Header delete: Delete delete_forever: Delete Forever - discussions: Discussions # Referenced by flarum-statistics.yml + discussions: Discussions # Referenced by flarum-statistics.yml edit: Edit edit_user: Edit User email: Email @@ -714,25 +729,25 @@ core: mark_all_as_read: Mark All as Read next_page: Next Page notifications: Notifications - okay: OK # Referenced by flarum-tags.yml + okay: OK # Referenced by flarum-tags.yml password: Password - posts: Posts # Referenced by flarum-statistics.yml + posts: Posts # Referenced by flarum-statistics.yml previous_page: Previous Page remove: Remove rename: Rename - reply: Reply # Referenced by flarum-mentions.yml + reply: Reply # Referenced by flarum-mentions.yml reset_your_password: Reset Your Password restore: Restore - save_changes: Save Changes # Referenced by flarum-suspend.yml, flarum-tags.yml + save_changes: Save Changes # Referenced by flarum-suspend.yml, flarum-tags.yml settings: Settings sign_up: Sign Up - some_others: "{count, plural, one {# other} other {# others}}" # Referenced by flarum-likes.yml, flarum-mentions.yml + some_others: "{count, plural, one {# other} other {# others}}" # Referenced by flarum-likes.yml, flarum-mentions.yml start_a_discussion: Start a Discussion username: Username - users: Users # Referenced by flarum-statistics.yml + users: Users # Referenced by flarum-statistics.yml view: View write_a_reply: Write a Reply... - you: You # Referenced by flarum-likes.yml, flarum-mentions.yml + you: You # Referenced by flarum-likes.yml, flarum-mentions.yml ## # GROUP NAMES - These keys are translated at the back end.