UserTableView: Show user name in table view (#18108)

* refactor to multiple rows

* added name for org user struct

* added name getorgusers

* added user name to tableview

* made test pass

* updated userMocks to user name field

* added missing UsersTable snapshot

* added name on teammembers page, be able to search query for name, login and email

* added the updated snapshots

* conform to same sorting as output form

* conform to previous way of using it

* sort first by login and after by email, as it was before
This commit is contained in:
Eric Leijonmarck 2019-11-21 11:44:46 +01:00 committed by Sofia Papagiannaki
parent e33cf32b97
commit f05607d4c0
19 changed files with 91 additions and 13 deletions

View File

@ -111,6 +111,7 @@ type OrgUserDTO struct {
OrgId int64 `json:"orgId"`
UserId int64 `json:"userId"`
Email string `json:"email"`
Name string `json:"name"`
AvatarUrl string `json:"avatarUrl"`
Login string `json:"login"`
Role string `json:"role"`

View File

@ -70,6 +70,7 @@ type TeamMemberDTO struct {
External bool `json:"-"`
AuthModule string `json:"auth_module"`
Email string `json:"email"`
Name string `json:"name"`
Login string `json:"login"`
AvatarUrl string `json:"avatarUrl"`
Labels []string `json:"labels"`

View File

@ -120,7 +120,15 @@ func GetOrgUsers(query *m.GetOrgUsersQuery) error {
sess.Limit(query.Limit, 0)
}
sess.Cols("org_user.org_id", "org_user.user_id", "user.email", "user.login", "org_user.role", "user.last_seen_at")
sess.Cols(
"org_user.org_id",
"org_user.user_id",
"user.email",
"user.name",
"user.login",
"org_user.role",
"user.last_seen_at",
)
sess.Asc("user.email", "user.login")
if err := sess.Find(&query.Result); err != nil {

View File

@ -387,7 +387,17 @@ func GetTeamMembers(query *models.GetTeamMembersQuery) error {
if query.External {
sess.Where("team_member.external=?", dialect.BooleanStr(true))
}
sess.Cols("team_member.org_id", "team_member.team_id", "team_member.user_id", "user.email", "user.login", "team_member.external", "team_member.permission", "user_auth.auth_module")
sess.Cols(
"team_member.org_id",
"team_member.team_id",
"team_member.user_id",
"user.email",
"user.name",
"user.login",
"team_member.external",
"team_member.permission",
"user_auth.auth_module",
)
sess.Asc("user.login", "user.email")
err := sess.Find(&query.Result)

View File

@ -74,8 +74,9 @@ describe('Functions', () => {
teamId: 2,
avatarUrl: '',
email: 'user@user.org',
labels: [],
login: 'member',
name: 'member',
labels: [],
permission: TeamPermissionLevel.Member,
};
const { instance } = setup({ member });

View File

@ -82,6 +82,7 @@ export class TeamMemberRow extends PureComponent<Props> {
</td>
<td>{member.login}</td>
<td>{member.email}</td>
<td>{member.name}</td>
{this.renderPermissions(member)}
{syncEnabled && this.renderLabels(member.labels)}
<td className="text-right">

View File

@ -115,8 +115,9 @@ export class TeamMembers extends PureComponent<Props, State> {
<thead>
<tr>
<th />
<th>Name</th>
<th>Login</th>
<th>Email</th>
<th>Name</th>
<WithFeatureToggle featureToggle={editorsCanAdmin}>
<th>Permission</th>
</WithFeatureToggle>

View File

@ -36,6 +36,7 @@ export const getMockTeamMembers = (amount: number, teamAdminId: number): TeamMem
teamId: 1,
avatarUrl: 'some/url/',
email: 'test@test.com',
name: 'testName',
login: `testUser-${i}`,
labels: ['label 1', 'label 2'],
permission: i === teamAdminId ? TeamPermissionLevel.Admin : TeamPermissionLevel.Member,
@ -51,6 +52,7 @@ export const getMockTeamMember = (): TeamMember => {
teamId: 1,
avatarUrl: 'some/url/',
email: 'test@test.com',
name: 'testName',
login: 'testUser',
labels: [],
permission: TeamPermissionLevel.Member,

View File

@ -18,6 +18,9 @@ exports[`Render should render team members when sync enabled 1`] = `
<td>
test@test.com
</td>
<td>
testName
</td>
<Component
featureToggle={false}
>
@ -71,6 +74,9 @@ exports[`Render when feature toggle editorsCanAdmin is turned off should not ren
<td>
test@test.com
</td>
<td>
testName
</td>
<Component
featureToggle={false}
>
@ -157,6 +163,9 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render p
<td>
test@test.com
</td>
<td>
testName
</td>
<Component
featureToggle={true}
>
@ -243,6 +252,9 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render s
<td>
test@test.com
</td>
<td>
testName
</td>
<Component
featureToggle={true}
>

View File

@ -64,11 +64,14 @@ exports[`Render should render component 1`] = `
<tr>
<th />
<th>
Name
Login
</th>
<th>
Email
</th>
<th>
Name
</th>
<Component
featureToggle={false}
>
@ -155,11 +158,14 @@ exports[`Render should render team members 1`] = `
<tr>
<th />
<th>
Name
Login
</th>
<th>
Email
</th>
<th>
Name
</th>
<Component
featureToggle={false}
>
@ -189,6 +195,7 @@ exports[`Render should render team members 1`] = `
"label 2",
],
"login": "testUser-1",
"name": "testName",
"permission": 0,
"teamId": 1,
"userId": 1,
@ -209,6 +216,7 @@ exports[`Render should render team members 1`] = `
"label 2",
],
"login": "testUser-2",
"name": "testName",
"permission": 0,
"teamId": 1,
"userId": 2,
@ -229,6 +237,7 @@ exports[`Render should render team members 1`] = `
"label 2",
],
"login": "testUser-3",
"name": "testName",
"permission": 0,
"teamId": 1,
"userId": 3,
@ -249,6 +258,7 @@ exports[`Render should render team members 1`] = `
"label 2",
],
"login": "testUser-4",
"name": "testName",
"permission": 0,
"teamId": 1,
"userId": 4,
@ -269,6 +279,7 @@ exports[`Render should render team members 1`] = `
"label 2",
],
"login": "testUser-5",
"name": "testName",
"permission": 4,
"teamId": 1,
"userId": 5,

View File

@ -26,7 +26,7 @@ export const getTeamMembers = (state: TeamState) => {
const regex = RegExp(state.searchMemberQuery, 'i');
return state.members.filter(member => {
return regex.test(member.login) || regex.test(member.email);
return regex.test(member.login) || regex.test(member.email) || regex.test(member.name);
});
};

View File

@ -49,7 +49,7 @@ export class UsersActionBar extends PureComponent<Props> {
inputClassName="gf-form-input width-20"
value={searchQuery}
onChange={setUsersSearchQuery}
placeholder="Filter by name or type"
placeholder="Filter by email, login or name"
/>
{pendingInvitesCount > 0 && (
<div style={{ marginLeft: '1rem' }}>

View File

@ -17,6 +17,7 @@ const UsersTable: FC<Props> = props => {
<th />
<th>Login</th>
<th>Email</th>
<th>Name</th>
<th>Seen</th>
<th>Role</th>
<th style={{ width: '34px' }} />
@ -33,6 +34,7 @@ const UsersTable: FC<Props> = props => {
<td>
<span className="ellipsis">{user.email}</span>
</td>
<td>{user.name}</td>
<td>{user.lastSeenAtAge}</td>
<td>
<div className="gf-form-select-wrapper width-12">

View File

@ -5,6 +5,7 @@ export const getMockUsers = (amount: number) => {
users.push({
avatarUrl: 'url/to/avatar',
email: `user-${i}@test.com`,
name: `user-${i} test`,
lastSeenAt: '2018-10-01',
lastSeenAtAge: '',
login: `user-${i}`,
@ -21,6 +22,7 @@ export const getMockUser = () => {
return {
avatarUrl: 'url/to/avatar',
email: `user@test.com`,
name: 'user test',
lastSeenAt: '2018-10-01',
lastSeenAtAge: '',
login: `user`,

View File

@ -11,7 +11,7 @@ exports[`Render should render component 1`] = `
inputClassName="gf-form-input width-20"
labelClassName="gf-form--has-input-icon"
onChange={[MockFunction]}
placeholder="Filter by name or type"
placeholder="Filter by email, login or name"
value=""
/>
<div
@ -32,7 +32,7 @@ exports[`Render should render pending invites button 1`] = `
inputClassName="gf-form-input width-20"
labelClassName="gf-form--has-input-icon"
onChange={[MockFunction]}
placeholder="Filter by name or type"
placeholder="Filter by email, login or name"
value=""
/>
<div
@ -77,7 +77,7 @@ exports[`Render should show external user management button 1`] = `
inputClassName="gf-form-input width-20"
labelClassName="gf-form--has-input-icon"
onChange={[MockFunction]}
placeholder="Filter by name or type"
placeholder="Filter by email, login or name"
value=""
/>
<div
@ -104,7 +104,7 @@ exports[`Render should show invite button 1`] = `
inputClassName="gf-form-input width-20"
labelClassName="gf-form--has-input-icon"
onChange={[MockFunction]}
placeholder="Filter by name or type"
placeholder="Filter by email, login or name"
value=""
/>
<div

View File

@ -13,6 +13,9 @@ exports[`Render should render component 1`] = `
<th>
Email
</th>
<th>
Name
</th>
<th>
Seen
</th>
@ -45,6 +48,9 @@ exports[`Render should render users table 1`] = `
<th>
Email
</th>
<th>
Name
</th>
<th>
Seen
</th>
@ -82,6 +88,9 @@ exports[`Render should render users table 1`] = `
user-0@test.com
</span>
</td>
<td>
user-0 test
</td>
<td />
<td>
<div
@ -145,6 +154,9 @@ exports[`Render should render users table 1`] = `
user-1@test.com
</span>
</td>
<td>
user-1 test
</td>
<td />
<td>
<div
@ -208,6 +220,9 @@ exports[`Render should render users table 1`] = `
user-2@test.com
</span>
</td>
<td>
user-2 test
</td>
<td />
<td>
<div
@ -271,6 +286,9 @@ exports[`Render should render users table 1`] = `
user-3@test.com
</span>
</td>
<td>
user-3 test
</td>
<td />
<td>
<div
@ -334,6 +352,9 @@ exports[`Render should render users table 1`] = `
user-4@test.com
</span>
</td>
<td>
user-4 test
</td>
<td />
<td>
<div
@ -397,6 +418,9 @@ exports[`Render should render users table 1`] = `
user-5@test.com
</span>
</td>
<td>
user-5 test
</td>
<td />
<td>
<div

View File

@ -4,7 +4,7 @@ export const getUsers = (state: UsersState) => {
const regex = new RegExp(state.searchQuery, 'i');
return state.users.filter(user => {
return regex.test(user.login) || regex.test(user.email);
return regex.test(user.login) || regex.test(user.email) || regex.test(user.name);
});
};

View File

@ -14,6 +14,7 @@ export interface TeamMember {
teamId: number;
avatarUrl: string;
email: string;
name: string;
login: string;
labels: string[];
permission: number;

View File

@ -6,6 +6,7 @@ export interface OrgUser {
lastSeenAt: string;
lastSeenAtAge: string;
login: string;
name: string;
orgId: number;
role: string;
userId: number;