mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Extracted role selector to <GhRoleSelection>
component
refs https://github.com/TryGhost/Team/issues/572 - preparation for re-using the new role selector in a model when changing an existing user's role
This commit is contained in:
parent
80357855aa
commit
e7ac8731b0
4 changed files with 213 additions and 191 deletions
154
ghost/admin/app/components/gh-role-selection.hbs
Normal file
154
ghost/admin/app/components/gh-role-selection.hbs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
<div class="gh-roles-container" {{did-insert (perform this.fetchRolesTask)}}>
|
||||||
|
{{#if this.fetchRolesTask.isRunning}}
|
||||||
|
<GhLoadingSpinner />
|
||||||
|
{{else}}
|
||||||
|
<div class="gh-radio {{if (eq @selected.name "Contributor") "active"}}" {{on "click" (fn this.setRole "Contributor")}} data-test-option="Contributor">
|
||||||
|
<div class="gh-radio-button"></div>
|
||||||
|
<div class="gh-radio-content">
|
||||||
|
<div class="gh-radio-label">Contributor</div>
|
||||||
|
<div class="gh-radio-desc">Can create and edit their own posts, but cannot publish. An Editor needs to approve and publish for them.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{!-- Inner container collapses height to the SVG so popover can align correctly --}}
|
||||||
|
<div>
|
||||||
|
{{svg-jar "info"}}
|
||||||
|
<EmberPopover @tooltipClass="popover" @arrowClass="popover-arrow" @side="left">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Settings</td>
|
||||||
|
<td>View and edit own profile</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Posts</td>
|
||||||
|
<td>Create and edit own draft posts</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</EmberPopover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gh-radio {{if (eq @selected.name "Author") "active"}}" {{on "click" (fn this.setRole "Author")}} data-test-option="Author">
|
||||||
|
<div class="gh-radio-button"></div>
|
||||||
|
<div class="gh-radio-content">
|
||||||
|
<div class="gh-radio-label">Author</div>
|
||||||
|
<div class="gh-radio-desc">A trusted user who can create, edit and publish their own posts, but can’t modify others.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{!-- Inner container collapses height to the SVG so popover can align correctly --}}
|
||||||
|
<div>
|
||||||
|
{{svg-jar "info"}}
|
||||||
|
<EmberPopover @tooltipClass="popover" @arrowClass="popover-arrow" @side="left">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Settings</td>
|
||||||
|
<td>View and edit own profile</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Users</td>
|
||||||
|
<td>Browse users</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Posts</td>
|
||||||
|
<td>View, edit and publish own posts, generate slugs</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Tags</td>
|
||||||
|
<td>Add tags</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</EmberPopover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gh-radio {{if (eq @selected.name "Editor") "active"}}" {{on "click" (fn this.setRole "Editor")}} data-test-option="Editor">
|
||||||
|
<div class="gh-radio-button"></div>
|
||||||
|
<div class="gh-radio-content">
|
||||||
|
<div class="gh-radio-label">Editor</div>
|
||||||
|
<div class="gh-radio-desc">Can invite and manage other Authors and Contributors, as well as edit and publish any posts on the site.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{!-- Inner container collapses height to the SVG so popover can align correctly --}}
|
||||||
|
<div>
|
||||||
|
{{svg-jar "info"}}
|
||||||
|
<EmberPopover @tooltipClass="popover" @arrowClass="popover-arrow" @side="left">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Settings</td>
|
||||||
|
<td>View and edit own profile</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Users</td>
|
||||||
|
<td>Browse users, manage authors and contributors (invite, revoke, delete)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Posts</td>
|
||||||
|
<td>Create, publish, edit and delete all posts, generate slugs</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Tags</td>
|
||||||
|
<td>Edit, add and delete tags</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</EmberPopover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gh-radio {{if (eq @selected.name "Administrator") "active"}}" {{on "click" (fn this.setRole "Administrator")}} data-test-option="Administrator">
|
||||||
|
<div class="gh-radio-button"></div>
|
||||||
|
<div class="gh-radio-content">
|
||||||
|
<div class="gh-radio-label">Administrator</div>
|
||||||
|
<div class="gh-radio-desc">Trusted staff user who should be able to manage all content and users, as well as site settings and options.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{!-- Inner container collapses height to the SVG so popover can align correctly --}}
|
||||||
|
<div>
|
||||||
|
{{svg-jar "info"}}
|
||||||
|
<EmberPopover @tooltipClass="popover" @arrowClass="popover-arrow" @side="left">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Settings</td>
|
||||||
|
<td>Access all except Stripe settings</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Users</td>
|
||||||
|
<td>Manage all users (invite, revoke, delete)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Posts</td>
|
||||||
|
<td>Create, publish, edit and delete all posts, generate slugs</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Tags</td>
|
||||||
|
<td>Edit, add and delete tags</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Database</td>
|
||||||
|
<td>Import, export and delete all content</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="left">Email</td>
|
||||||
|
<td>Send newsletters and test emails</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</EmberPopover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="gh-content-box pa" hidden={{if this.limitErrorMessage false true}}>
|
||||||
|
{{html-safe this.limitErrorMessage}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
54
ghost/admin/app/components/gh-role-selection.js
Normal file
54
ghost/admin/app/components/gh-role-selection.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import Component from '@glimmer/component';
|
||||||
|
import {action} from '@ember/object';
|
||||||
|
import {inject as service} from '@ember/service';
|
||||||
|
import {task} from 'ember-concurrency-decorators';
|
||||||
|
import {tracked} from '@glimmer/tracking';
|
||||||
|
|
||||||
|
const DEFAULT_ROLE_NAME = 'Contributor';
|
||||||
|
|
||||||
|
export default class GhRoleSelectionComponent extends Component {
|
||||||
|
@service limit;
|
||||||
|
@service notifications;
|
||||||
|
@service store;
|
||||||
|
|
||||||
|
@tracked roles = [];
|
||||||
|
@tracked limitErrorMessage = null;
|
||||||
|
|
||||||
|
@action
|
||||||
|
async setRole(roleName) {
|
||||||
|
const role = this.roles.findBy('name', roleName);
|
||||||
|
this.args.setRole(role);
|
||||||
|
return this.validateRole();
|
||||||
|
}
|
||||||
|
|
||||||
|
@task
|
||||||
|
*fetchRolesTask() {
|
||||||
|
const roles = yield this.store.query('role', {permissions: 'assign'});
|
||||||
|
const defaultRole = roles.findBy('name', DEFAULT_ROLE_NAME);
|
||||||
|
|
||||||
|
this.roles = roles;
|
||||||
|
|
||||||
|
if (!this.args.role && defaultRole) {
|
||||||
|
this.args.setRole(defaultRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async validateRole(role) {
|
||||||
|
if (role.name !== 'Contributor'
|
||||||
|
&& this.limit.limiter && this.limit.limiter.isLimited('staff')) {
|
||||||
|
try {
|
||||||
|
await this.limit.limiter.errorIfWouldGoOverLimit('staff');
|
||||||
|
|
||||||
|
this.limitErrorMessage = null;
|
||||||
|
} catch (error) {
|
||||||
|
if (error.errorType === 'HostLimitError') {
|
||||||
|
this.limitErrorMessage = error.message;
|
||||||
|
} else {
|
||||||
|
this.notifications.showAPIError(error, {key: 'staff.limit'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.limitErrorMessage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,156 +30,10 @@
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="email" />
|
<GhErrorMessage @errors={{this.errors}} @property="email" />
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
|
|
||||||
<div class="gh-roles-container">
|
<GhRoleSelection
|
||||||
<div class="gh-radio {{if (eq this.role.name "Contributor") "active"}}" {{on "click" (fn this.setRole "Contributor")}} data-test-option="Contributor">
|
@selected={{this.role}}
|
||||||
<div class="gh-radio-button"></div>
|
@setRole={{this.setRole}}
|
||||||
<div class="gh-radio-content">
|
/>
|
||||||
<div class="gh-radio-label">Contributor</div>
|
|
||||||
<div class="gh-radio-desc">Can create and edit their own posts, but cannot publish. An Editor needs to approve and publish for them.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{!-- Inner container collapses height to the SVG so popover can align correctly --}}
|
|
||||||
<div>
|
|
||||||
{{svg-jar "info"}}
|
|
||||||
<EmberPopover @tooltipClass="popover" @arrowClass="popover-arrow" @side="left">
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Settings</td>
|
|
||||||
<td>View and edit own profile</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Posts</td>
|
|
||||||
<td>Create and edit own draft posts</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</EmberPopover>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="gh-radio {{if (eq this.role.name "Author") "active"}}" {{on "click" (fn this.setRole "Author")}} data-test-option="Author">
|
|
||||||
<div class="gh-radio-button"></div>
|
|
||||||
<div class="gh-radio-content">
|
|
||||||
<div class="gh-radio-label">Author</div>
|
|
||||||
<div class="gh-radio-desc">A trusted user who can create, edit and publish their own posts, but can’t modify others.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{!-- Inner container collapses height to the SVG so popover can align correctly --}}
|
|
||||||
<div>
|
|
||||||
{{svg-jar "info"}}
|
|
||||||
<EmberPopover @tooltipClass="popover" @arrowClass="popover-arrow" @side="left">
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Settings</td>
|
|
||||||
<td>View and edit own profile</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Users</td>
|
|
||||||
<td>Browse users</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Posts</td>
|
|
||||||
<td>View, edit and publish own posts, generate slugs</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Tags</td>
|
|
||||||
<td>Add tags</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</EmberPopover>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="gh-radio {{if (eq this.role.name "Editor") "active"}}" {{on "click" (fn this.setRole "Editor")}} data-test-option="Editor">
|
|
||||||
<div class="gh-radio-button"></div>
|
|
||||||
<div class="gh-radio-content">
|
|
||||||
<div class="gh-radio-label">Editor</div>
|
|
||||||
<div class="gh-radio-desc">Can invite and manage other Authors and Contributors, as well as edit and publish any posts on the site.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{!-- Inner container collapses height to the SVG so popover can align correctly --}}
|
|
||||||
<div>
|
|
||||||
{{svg-jar "info"}}
|
|
||||||
<EmberPopover @tooltipClass="popover" @arrowClass="popover-arrow" @side="left">
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Settings</td>
|
|
||||||
<td>View and edit own profile</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Users</td>
|
|
||||||
<td>Browse users, manage authors and contributors (invite, revoke, delete)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Posts</td>
|
|
||||||
<td>Create, publish, edit and delete all posts, generate slugs</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Tags</td>
|
|
||||||
<td>Edit, add and delete tags</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</EmberPopover>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="gh-radio {{if (eq this.role.name "Administrator") "active"}}" {{on "click" (fn this.setRole "Administrator")}} data-test-option="Administrator">
|
|
||||||
<div class="gh-radio-button"></div>
|
|
||||||
<div class="gh-radio-content">
|
|
||||||
<div class="gh-radio-label">Administrator</div>
|
|
||||||
<div class="gh-radio-desc">Trusted staff user who should be able to manage all content and users, as well as site settings and options.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{!-- Inner container collapses height to the SVG so popover can align correctly --}}
|
|
||||||
<div>
|
|
||||||
{{svg-jar "info"}}
|
|
||||||
<EmberPopover @tooltipClass="popover" @arrowClass="popover-arrow" @side="left">
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Settings</td>
|
|
||||||
<td>Access all except Stripe settings</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Users</td>
|
|
||||||
<td>Manage all users (invite, revoke, delete)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Posts</td>
|
|
||||||
<td>Create, publish, edit and delete all posts, generate slugs</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Tags</td>
|
|
||||||
<td>Edit, add and delete tags</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Database</td>
|
|
||||||
<td>Import, export and delete all content</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="left">Email</td>
|
|
||||||
<td>Send newsletters and test emails</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</EmberPopover>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="gh-content-box pa" hidden={{if this.limitErrorMessage false true}}>
|
|
||||||
{{html-safe this.limitErrorMessage}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,9 @@ export default ModalComponent.extend(ValidationEngine, {
|
||||||
classNames: 'modal-content invite-new-user',
|
classNames: 'modal-content invite-new-user',
|
||||||
|
|
||||||
role: null,
|
role: null,
|
||||||
roles: null,
|
|
||||||
|
|
||||||
limitErrorMessage: null,
|
|
||||||
|
|
||||||
validationType: 'inviteUser',
|
validationType: 'inviteUser',
|
||||||
|
|
||||||
didInsertElement() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.fetchRoles.perform();
|
|
||||||
},
|
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
// TODO: this should not be needed, ValidationEngine acts as a
|
// TODO: this should not be needed, ValidationEngine acts as a
|
||||||
|
@ -42,32 +34,11 @@ export default ModalComponent.extend(ValidationEngine, {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setRole: action(function (roleName) {
|
setRole: action(function (role) {
|
||||||
const role = this.roles.findBy('name', roleName);
|
|
||||||
this.set('role', role);
|
this.set('role', role);
|
||||||
this.errors.remove('role');
|
this.errors.remove('role');
|
||||||
this.validateRole();
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
async validateRole() {
|
|
||||||
if (this.get('role.name') !== 'Contributor'
|
|
||||||
&& this.limit.limiter && this.limit.limiter.isLimited('staff')) {
|
|
||||||
try {
|
|
||||||
await this.limit.limiter.errorIfWouldGoOverLimit('staff');
|
|
||||||
|
|
||||||
this.set('limitErrorMessage', null);
|
|
||||||
} catch (error) {
|
|
||||||
if (error.errorType === 'HostLimitError') {
|
|
||||||
this.set('limitErrorMessage', error.message);
|
|
||||||
} else {
|
|
||||||
this.notifications.showAPIError(error, {key: 'staff.limit'});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.set('limitErrorMessage', null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
validate() {
|
validate() {
|
||||||
let email = this.email;
|
let email = this.email;
|
||||||
|
|
||||||
|
@ -103,17 +74,6 @@ export default ModalComponent.extend(ValidationEngine, {
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchRoles: task(function * () {
|
|
||||||
let roles = yield this.store.query('role', {permissions: 'assign'});
|
|
||||||
let defaultRole = roles.findBy('name', 'Contributor');
|
|
||||||
|
|
||||||
this.set('roles', roles);
|
|
||||||
|
|
||||||
if (!this.role) {
|
|
||||||
this.set('role', defaultRole);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
sendInvitation: task(function* () {
|
sendInvitation: task(function* () {
|
||||||
let email = this.email;
|
let email = this.email;
|
||||||
let role = this.role;
|
let role = this.role;
|
||||||
|
|
Loading…
Add table
Reference in a new issue