aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps/account
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web/src/main/js/apps/account')
-rw-r--r--server/sonar-web/src/main/js/apps/account/account.css2
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Password.js4
-rw-r--r--server/sonar-web/src/main/js/apps/account/components/Security.js4
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js46
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/Notifications.js7
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/Projects.js50
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap126
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap5
-rw-r--r--server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap288
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx33
-rw-r--r--server/sonar-web/src/main/js/apps/account/profile/Profile.js36
-rw-r--r--server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs142
13 files changed, 380 insertions, 368 deletions
diff --git a/server/sonar-web/src/main/js/apps/account/account.css b/server/sonar-web/src/main/js/apps/account/account.css
index 12c3cabf574..73d42282e13 100644
--- a/server/sonar-web/src/main/js/apps/account/account.css
+++ b/server/sonar-web/src/main/js/apps/account/account.css
@@ -8,7 +8,7 @@
padding-top: 20px;
padding-bottom: 20px;
border-bottom: 1px solid var(--barBorderColor);
- background-color: var(--barBackgroundColor);
+ background-color: #fff;
}
.account-nav {
diff --git a/server/sonar-web/src/main/js/apps/account/components/Password.js b/server/sonar-web/src/main/js/apps/account/components/Password.js
index dec082bc69b..6e3bb3c3c69 100644
--- a/server/sonar-web/src/main/js/apps/account/components/Password.js
+++ b/server/sonar-web/src/main/js/apps/account/components/Password.js
@@ -70,10 +70,10 @@ export default class Password extends Component {
const { success, errors } = this.state;
return (
- <section>
+ <section className="boxed-group">
<h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2>
- <form onSubmit={this.handleChangePassword}>
+ <form className="boxed-group-inner" onSubmit={this.handleChangePassword}>
{success && (
<div className="alert alert-success">{translate('my_profile.password.changed')}</div>
)}
diff --git a/server/sonar-web/src/main/js/apps/account/components/Security.js b/server/sonar-web/src/main/js/apps/account/components/Security.js
index d52a3b6e1ea..3006ca55f1a 100644
--- a/server/sonar-web/src/main/js/apps/account/components/Security.js
+++ b/server/sonar-web/src/main/js/apps/account/components/Security.js
@@ -31,11 +31,7 @@ function Security(props) {
return (
<div className="account-body account-container">
<Helmet title={translate('my_account.security')} />
-
<Tokens user={user} />
-
- {user.local && <hr className="account-separator" />}
-
{user.local && <Password user={user} />}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js b/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js
index d7ba3d35197..294c2c209c6 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js
+++ b/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.js
@@ -46,30 +46,32 @@ type Props = {
function GlobalNotifications(props /*: Props */) {
return (
- <section>
- <h2 className="spacer-bottom">{translate('my_profile.overall_notifications.title')}</h2>
+ <section className="boxed-group">
+ <h2>{translate('my_profile.overall_notifications.title')}</h2>
- <table className="form">
- <thead>
- <tr>
- <th />
- {props.channels.map(channel => (
- <th key={channel} className="text-center">
- <h4>{translate('notification.channel', channel)}</h4>
- </th>
- ))}
- </tr>
- </thead>
+ <div className="boxed-group-inner">
+ <table className="form">
+ <thead>
+ <tr>
+ <th />
+ {props.channels.map(channel => (
+ <th key={channel} className="text-center">
+ <h4>{translate('notification.channel', channel)}</h4>
+ </th>
+ ))}
+ </tr>
+ </thead>
- <NotificationsList
- notifications={props.notifications}
- channels={props.channels}
- types={props.types}
- checkboxId={(d, c) => `global-notification-${d}-${c}`}
- onAdd={props.addNotification}
- onRemove={props.removeNotification}
- />
- </table>
+ <NotificationsList
+ notifications={props.notifications}
+ channels={props.channels}
+ types={props.types}
+ checkboxId={(d, c) => `global-notification-${d}-${c}`}
+ onAdd={props.addNotification}
+ onRemove={props.removeNotification}
+ />
+ </table>
+ </div>
</section>
);
}
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/Notifications.js b/server/sonar-web/src/main/js/apps/account/notifications/Notifications.js
index aa2c8d1179e..6e5fed53bcc 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/Notifications.js
+++ b/server/sonar-web/src/main/js/apps/account/notifications/Notifications.js
@@ -40,13 +40,8 @@ class Notifications extends React.PureComponent {
return (
<div className="account-body account-container">
<Helmet title={translate('my_account.notifications')} />
-
- <p className="big-spacer-bottom">{translate('notification.dispatcher.information')}</p>
-
+ <p className="alert alert-info">{translate('notification.dispatcher.information')}</p>
<GlobalNotifications />
-
- <hr className="account-separator" />
-
<Projects />
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/Projects.js b/server/sonar-web/src/main/js/apps/account/notifications/Projects.js
index 14a7f74020c..5345b55591a 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/Projects.js
+++ b/server/sonar-web/src/main/js/apps/account/notifications/Projects.js
@@ -113,30 +113,32 @@ class Projects extends React.PureComponent {
const allProjects = [...this.props.projects, ...this.state.addedProjects];
return (
- <section>
- <h2 className="spacer-bottom">{translate('my_profile.per_project_notifications.title')}</h2>
-
- {allProjects.length === 0 && (
- <div className="note">{translate('my_account.no_project_notifications')}</div>
- )}
-
- {allProjects.map(project => <ProjectNotifications key={project.key} project={project} />)}
-
- <div className="spacer-top panel bg-muted">
- <span className="text-middle spacer-right">
- {translate('my_account.set_notifications_for')}:
- </span>
- <AsyncSelect
- autoload={false}
- cache={false}
- name="new_project"
- style={{ width: '300px' }}
- loadOptions={this.loadOptions}
- minimumInput={2}
- optionRenderer={this.renderOption}
- onChange={this.handleAddProject}
- placeholder={translate('my_account.search_project')}
- />
+ <section className="boxed-group">
+ <h2>{translate('my_profile.per_project_notifications.title')}</h2>
+
+ <div className="boxed-group-inner">
+ {allProjects.length === 0 && (
+ <div className="note">{translate('my_account.no_project_notifications')}</div>
+ )}
+
+ {allProjects.map(project => <ProjectNotifications key={project.key} project={project} />)}
+
+ <div className="spacer-top panel bg-muted">
+ <span className="text-middle spacer-right">
+ {translate('my_account.set_notifications_for')}:
+ </span>
+ <AsyncSelect
+ autoload={false}
+ cache={false}
+ name="new_project"
+ style={{ width: '300px' }}
+ loadOptions={this.loadOptions}
+ minimumInput={2}
+ optionRenderer={this.renderOption}
+ onChange={this.handleAddProject}
+ placeholder={translate('my_account.search_project')}
+ />
+ </div>
</div>
</section>
);
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap
index 4a7d7d10c5a..64a62011d96 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.js.snap
@@ -1,69 +1,73 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should match snapshot 1`] = `
-<section>
- <h2
- className="spacer-bottom"
- >
+<section
+ className="boxed-group"
+>
+ <h2>
my_profile.overall_notifications.title
</h2>
- <table
- className="form"
+ <div
+ className="boxed-group-inner"
>
- <thead>
- <tr>
- <th />
- <th
- className="text-center"
- key="channel1"
- >
- <h4>
- notification.channel.channel1
- </h4>
- </th>
- <th
- className="text-center"
- key="channel2"
- >
- <h4>
- notification.channel.channel2
- </h4>
- </th>
- </tr>
- </thead>
- <NotificationsList
- channels={
- Array [
- "channel1",
- "channel2",
- ]
- }
- checkboxId={[Function]}
- notifications={
- Array [
- Object {
- "channel": "channel1",
- "type": "type1",
- },
- Object {
- "channel": "channel1",
- "type": "type2",
- },
- Object {
- "channel": "channel2",
- "type": "type2",
- },
- ]
- }
- onAdd={[Function]}
- onRemove={[Function]}
- types={
- Array [
- "type1",
- "type2",
- ]
- }
- />
- </table>
+ <table
+ className="form"
+ >
+ <thead>
+ <tr>
+ <th />
+ <th
+ className="text-center"
+ key="channel1"
+ >
+ <h4>
+ notification.channel.channel1
+ </h4>
+ </th>
+ <th
+ className="text-center"
+ key="channel2"
+ >
+ <h4>
+ notification.channel.channel2
+ </h4>
+ </th>
+ </tr>
+ </thead>
+ <NotificationsList
+ channels={
+ Array [
+ "channel1",
+ "channel2",
+ ]
+ }
+ checkboxId={[Function]}
+ notifications={
+ Array [
+ Object {
+ "channel": "channel1",
+ "type": "type1",
+ },
+ Object {
+ "channel": "channel1",
+ "type": "type2",
+ },
+ Object {
+ "channel": "channel2",
+ "type": "type2",
+ },
+ ]
+ }
+ onAdd={[Function]}
+ onRemove={[Function]}
+ types={
+ Array [
+ "type1",
+ "type2",
+ ]
+ }
+ />
+ </table>
+ </div>
</section>
`;
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap
index 8541cc01be7..855ccecb356 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Notifications-test.js.snap
@@ -10,14 +10,11 @@ exports[`should match snapshot 1`] = `
title="my_account.notifications"
/>
<p
- className="big-spacer-bottom"
+ className="alert alert-info"
>
notification.dispatcher.information
</p>
<Connect(GlobalNotifications) />
- <hr
- className="account-separator"
- />
<Connect(Projects) />
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap
index 3d6b8b28eb1..7f2fb250868 100644
--- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/Projects-test.js.snap
@@ -1,178 +1,190 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render projects 1`] = `
-<section>
- <h2
- className="spacer-bottom"
- >
+<section
+ className="boxed-group"
+>
+ <h2>
my_profile.per_project_notifications.title
</h2>
- <Connect(ProjectNotifications)
- key="foo"
- project={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="bar"
- project={
- Object {
- "key": "bar",
- "name": "Bar",
- }
- }
- />
<div
- className="spacer-top panel bg-muted"
+ className="boxed-group-inner"
>
- <span
- className="text-middle spacer-right"
- >
- my_account.set_notifications_for
- :
- </span>
- <AsyncSelect
- autoload={false}
- cache={false}
- loadOptions={[Function]}
- minimumInput={2}
- name="new_project"
- onChange={[Function]}
- optionRenderer={[Function]}
- placeholder="my_account.search_project"
- style={
+ <Connect(ProjectNotifications)
+ key="foo"
+ project={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <Connect(ProjectNotifications)
+ key="bar"
+ project={
Object {
- "width": "300px",
+ "key": "bar",
+ "name": "Bar",
}
}
/>
+ <div
+ className="spacer-top panel bg-muted"
+ >
+ <span
+ className="text-middle spacer-right"
+ >
+ my_account.set_notifications_for
+ :
+ </span>
+ <AsyncSelect
+ autoload={false}
+ cache={false}
+ loadOptions={[Function]}
+ minimumInput={2}
+ name="new_project"
+ onChange={[Function]}
+ optionRenderer={[Function]}
+ placeholder="my_account.search_project"
+ style={
+ Object {
+ "width": "300px",
+ }
+ }
+ />
+ </div>
</div>
</section>
`;
exports[`should render projects 2`] = `
-<section>
- <h2
- className="spacer-bottom"
- >
+<section
+ className="boxed-group"
+>
+ <h2>
my_profile.per_project_notifications.title
</h2>
- <Connect(ProjectNotifications)
- key="foo"
- project={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="bar"
- project={
- Object {
- "key": "bar",
- "name": "Bar",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="qux"
- project={
- Object {
- "key": "qux",
- "name": "Qux",
- }
- }
- />
<div
- className="spacer-top panel bg-muted"
+ className="boxed-group-inner"
>
- <span
- className="text-middle spacer-right"
- >
- my_account.set_notifications_for
- :
- </span>
- <AsyncSelect
- autoload={false}
- cache={false}
- loadOptions={[Function]}
- minimumInput={2}
- name="new_project"
- onChange={[Function]}
- optionRenderer={[Function]}
- placeholder="my_account.search_project"
- style={
+ <Connect(ProjectNotifications)
+ key="foo"
+ project={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <Connect(ProjectNotifications)
+ key="bar"
+ project={
+ Object {
+ "key": "bar",
+ "name": "Bar",
+ }
+ }
+ />
+ <Connect(ProjectNotifications)
+ key="qux"
+ project={
Object {
- "width": "300px",
+ "key": "qux",
+ "name": "Qux",
}
}
/>
+ <div
+ className="spacer-top panel bg-muted"
+ >
+ <span
+ className="text-middle spacer-right"
+ >
+ my_account.set_notifications_for
+ :
+ </span>
+ <AsyncSelect
+ autoload={false}
+ cache={false}
+ loadOptions={[Function]}
+ minimumInput={2}
+ name="new_project"
+ onChange={[Function]}
+ optionRenderer={[Function]}
+ placeholder="my_account.search_project"
+ style={
+ Object {
+ "width": "300px",
+ }
+ }
+ />
+ </div>
</div>
</section>
`;
exports[`should render projects 3`] = `
-<section>
- <h2
- className="spacer-bottom"
- >
+<section
+ className="boxed-group"
+>
+ <h2>
my_profile.per_project_notifications.title
</h2>
- <Connect(ProjectNotifications)
- key="foo"
- project={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="bar"
- project={
- Object {
- "key": "bar",
- "name": "Bar",
- }
- }
- />
- <Connect(ProjectNotifications)
- key="qux"
- project={
- Object {
- "key": "qux",
- "name": "Qux",
- }
- }
- />
<div
- className="spacer-top panel bg-muted"
+ className="boxed-group-inner"
>
- <span
- className="text-middle spacer-right"
- >
- my_account.set_notifications_for
- :
- </span>
- <AsyncSelect
- autoload={false}
- cache={false}
- loadOptions={[Function]}
- minimumInput={2}
- name="new_project"
- onChange={[Function]}
- optionRenderer={[Function]}
- placeholder="my_account.search_project"
- style={
+ <Connect(ProjectNotifications)
+ key="foo"
+ project={
Object {
- "width": "300px",
+ "key": "foo",
+ "name": "Foo",
}
}
/>
+ <Connect(ProjectNotifications)
+ key="bar"
+ project={
+ Object {
+ "key": "bar",
+ "name": "Bar",
+ }
+ }
+ />
+ <Connect(ProjectNotifications)
+ key="qux"
+ project={
+ Object {
+ "key": "qux",
+ "name": "Qux",
+ }
+ }
+ />
+ <div
+ className="spacer-top panel bg-muted"
+ >
+ <span
+ className="text-middle spacer-right"
+ >
+ my_account.set_notifications_for
+ :
+ </span>
+ <AsyncSelect
+ autoload={false}
+ cache={false}
+ loadOptions={[Function]}
+ minimumInput={2}
+ name="new_project"
+ onChange={[Function]}
+ optionRenderer={[Function]}
+ placeholder="my_account.search_project"
+ style={
+ Object {
+ "width": "300px",
+ }
+ }
+ />
+ </div>
</div>
</section>
`;
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx b/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx
index 5b0b8ccc367..42273f32553 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx
+++ b/server/sonar-web/src/main/js/apps/account/organizations/OrganizationsList.tsx
@@ -21,12 +21,17 @@ import * as React from 'react';
import { sortBy } from 'lodash';
import OrganizationCard from './OrganizationCard';
import { Organization } from '../../../app/types';
+import { translate } from '../../../helpers/l10n';
interface Props {
organizations: Organization[];
}
export default function OrganizationsList({ organizations }: Props) {
+ if (organizations.length === 0) {
+ return <div>{translate('my_account.organizations.no_results')}</div>;
+ }
+
return (
<ul className="account-projects-list">
{sortBy(organizations, organization => organization.name.toLocaleLowerCase()).map(
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
index e6f34fbd8e2..d63555b1574 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
+++ b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
@@ -87,29 +87,22 @@ class UserOrganizations extends React.PureComponent<Props, State> {
<div className="account-body account-container">
<Helmet title={translate('my_account.organizations')} />
- <header className="page-header">
- <h2 className="page-title">{translate('my_account.organizations')}</h2>
+ <div className="boxed-group">
{canCreateOrganizations && (
- <div className="page-actions">
- <button onClick={this.handleCreateClick}>{translate('create')}</button>
+ <div className="clearfix">
+ <div className="boxed-group-actions">
+ <button onClick={this.handleCreateClick}>{translate('create')}</button>
+ </div>
</div>
)}
- {this.props.organizations.length > 0 ? (
- <div className="page-description">
- {translate('my_account.organizations.description')}
- </div>
- ) : (
- <div className="page-description">
- {translate('my_account.organizations.no_results')}
- </div>
- )}
- </header>
-
- {this.state.loading ? (
- <i className="spinner" />
- ) : (
- <OrganizationsList organizations={this.props.organizations} />
- )}
+ <div className="boxed-group-inner">
+ {this.state.loading ? (
+ <i className="spinner" />
+ ) : (
+ <OrganizationsList organizations={this.props.organizations} />
+ )}
+ </div>
+ </div>
{this.state.createOrganization && (
<CreateOrganizationForm
diff --git a/server/sonar-web/src/main/js/apps/account/profile/Profile.js b/server/sonar-web/src/main/js/apps/account/profile/Profile.js
index 4996bfcd124..464f549d5bd 100644
--- a/server/sonar-web/src/main/js/apps/account/profile/Profile.js
+++ b/server/sonar-web/src/main/js/apps/account/profile/Profile.js
@@ -45,29 +45,31 @@ function Profile(props /*: Props */) {
return (
<div className="account-body account-container">
- <div className="spacer-bottom">
- {translate('login')}: <strong id="login">{user.login}</strong>
- </div>
+ <div className="boxed-group boxed-group-inner">
+ <div className="spacer-bottom">
+ {translate('login')}: <strong id="login">{user.login}</strong>
+ </div>
+
+ {!user.local &&
+ user.externalProvider !== 'sonarqube' && (
+ <div id="identity-provider" className="spacer-bottom">
+ <UserExternalIdentity user={user} />
+ </div>
+ )}
- {!user.local &&
- user.externalProvider !== 'sonarqube' && (
- <div id="identity-provider" className="spacer-bottom">
- <UserExternalIdentity user={user} />
+ {!!user.email && (
+ <div className="spacer-bottom">
+ {translate('my_profile.email')}: <strong id="email">{user.email}</strong>
</div>
)}
- {!!user.email && (
- <div className="spacer-bottom">
- {translate('my_profile.email')}: <strong id="email">{user.email}</strong>
- </div>
- )}
+ {!customOrganizations && <hr className="account-separator" />}
+ {!customOrganizations && <UserGroups groups={user.groups} />}
- {!customOrganizations && <hr className="account-separator" />}
- {!customOrganizations && <UserGroups groups={user.groups} />}
+ <hr />
- <hr className="account-separator" />
-
- <UserScmAccounts user={user} scmAccounts={user.scmAccounts} />
+ <UserScmAccounts user={user} scmAccounts={user.scmAccounts} />
+ </div>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs b/server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs
index 2c8da3e0297..65bbf91e160 100644
--- a/server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs
+++ b/server/sonar-web/src/main/js/apps/account/templates/account-tokens.hbs
@@ -1,77 +1,81 @@
-<h2 class="spacer-bottom">{{t 'users.tokens'}}</h2>
+<div class="boxed-group">
+ <h2>{{t 'users.tokens'}}</h2>
-<div class="big-spacer-bottom big-spacer-right markdown">
- <p>{{t 'my_account.tokens_description'}}</p>
-</div>
+<div class="boxed-group-inner">
+ <div class="big-spacer-bottom big-spacer-right markdown">
+ <p>{{t 'my_account.tokens_description'}}</p>
+ </div>
-{{#notNull tokens}}
- <table class="data">
- <thead>
- <tr>
- <th>{{t 'name'}}</th>
- <th class="text-right">{{t 'created'}}</th>
- <th>&nbsp;</th>
- </tr>
- </thead>
- <tbody>
- {{#each tokens}}
- <tr>
- <td>
- <div title="{{name}}">
- {{limitString name}}
- </div>
- </td>
- <td class="thin nowrap text-right">
- {{d createdAt}}
- </td>
- <td class="thin nowrap text-right">
- <div class="big-spacer-left">
- <form class="js-revoke-token-form" data-token="{{name}}">
- {{#if deleting}}
- <button class="button-red active input-small">{{t 'users.tokens.sure'}}</button>
- {{else}}
- <button class="button-red input-small">{{t 'users.tokens.revoke'}}</button>
- {{/if}}
- </form>
- </div>
- </td>
- </tr>
- {{else}}
+ {{#notNull tokens}}
+ <table class="data">
+ <thead>
<tr>
- <td colspan="3">
- <span class="note">{{t 'users.no_tokens'}}</span>
- </td>
+ <th>{{t 'name'}}</th>
+ <th class="text-right">{{t 'created'}}</th>
+ <th>&nbsp;</th>
</tr>
- {{/each}}
- </tbody>
- </table>
-{{/notNull}}
+ </thead>
+ <tbody>
+ {{#each tokens}}
+ <tr>
+ <td>
+ <div title="{{name}}">
+ {{limitString name}}
+ </div>
+ </td>
+ <td class="thin nowrap text-right">
+ {{d createdAt}}
+ </td>
+ <td class="thin nowrap text-right">
+ <div class="big-spacer-left">
+ <form class="js-revoke-token-form" data-token="{{name}}">
+ {{#if deleting}}
+ <button class="button-red active input-small">{{t 'users.tokens.sure'}}</button>
+ {{else}}
+ <button class="button-red input-small">{{t 'users.tokens.revoke'}}</button>
+ {{/if}}
+ </form>
+ </div>
+ </td>
+ </tr>
+ {{else}}
+ <tr>
+ <td colspan="3">
+ <span class="note">{{t 'users.no_tokens'}}</span>
+ </td>
+ </tr>
+ {{/each}}
+ </tbody>
+ </table>
+ {{/notNull}}
-{{#each errors}}
- <div class="alert alert-danger">{{msg}}</div>
-{{/each}}
+ {{#each errors}}
+ <div class="alert alert-danger">{{msg}}</div>
+ {{/each}}
-<form class="js-generate-token-form spacer-top panel bg-muted">
- <label>{{t 'users.generate_new_token'}}:</label>
- <input type="text" required maxlength="100" placeholder="{{t 'users.enter_token_name'}}">
- <button>{{t 'users.generate'}}</button>
-</form>
+ <form class="js-generate-token-form spacer-top panel bg-muted">
+ <label>{{t 'users.generate_new_token'}}:</label>
+ <input type="text" required maxlength="100" placeholder="{{t 'users.enter_token_name'}}">
+ <button>{{t 'users.generate'}}</button>
+ </form>
-{{#if newToken}}
- <div class="panel panel-white big-spacer-top">
- <div class="alert alert-warning">
- {{tp 'users.tokens.new_token_created' newToken.name}}
- </div>
+ {{#if newToken}}
+ <div class="panel panel-white big-spacer-top">
+ <div class="alert alert-warning">
+ {{tp 'users.tokens.new_token_created' newToken.name}}
+ </div>
- <table class="data">
- <tr>
- <td class="thin">
- <button class="js-copy-to-clipboard" data-clipboard-text="{{newToken.token}}">{{t 'copy'}}</button>
- </td>
- <td class="nowrap">
- <div class="monospaced text-success">{{newToken.token}}</div>
- </td>
- </tr>
- </table>
- </div>
-{{/if}}
+ <table class="data">
+ <tr>
+ <td class="thin">
+ <button class="js-copy-to-clipboard" data-clipboard-text="{{newToken.token}}">{{t 'copy'}}</button>
+ </td>
+ <td class="nowrap">
+ <div class="monospaced text-success">{{newToken.token}}</div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ {{/if}}
+</div>
+</div>