Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
3581d619
Unverified
Commit
3581d619
authored
Dec 14, 2018
by
Daniel Lee
Committed by
GitHub
Dec 14, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14499 from grafana/14483/copy-invite-link-fix
Fix for copy invite link
parents
82adf539
d37dae34
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
184 additions
and
306 deletions
+184
-306
public/app/features/users/InviteeRow.tsx
+57
-0
public/app/features/users/InviteesTable.test.tsx
+0
-1
public/app/features/users/InviteesTable.tsx
+4
-37
public/app/features/users/UsersListPage.test.tsx
+0
-1
public/app/features/users/UsersListPage.tsx
+2
-8
public/app/features/users/__mocks__/userMocks.ts
+1
-1
public/app/features/users/__snapshots__/InviteesTable.test.tsx.snap
+120
-258
No files found.
public/app/features/users/InviteeRow.tsx
0 → 100644
View file @
3581d619
import
React
,
{
createRef
,
PureComponent
}
from
'react'
;
import
{
connect
}
from
'react-redux'
;
import
{
Invitee
}
from
'app/types'
;
import
{
revokeInvite
}
from
'./state/actions'
;
export
interface
Props
{
invitee
:
Invitee
;
revokeInvite
:
typeof
revokeInvite
;
}
class
InviteeRow
extends
PureComponent
<
Props
>
{
private
copyUrlRef
=
createRef
<
HTMLTextAreaElement
>
();
copyToClipboard
=
()
=>
{
const
node
=
this
.
copyUrlRef
.
current
;
if
(
node
)
{
node
.
select
();
document
.
execCommand
(
'copy'
);
}
};
render
()
{
const
{
invitee
,
revokeInvite
}
=
this
.
props
;
return
(
<
tr
>
<
td
>
{
invitee
.
email
}
</
td
>
<
td
>
{
invitee
.
name
}
</
td
>
<
td
className=
"text-right"
>
<
button
className=
"btn btn-inverse btn-mini"
onClick=
{
this
.
copyToClipboard
}
>
<
textarea
readOnly=
{
true
}
value=
{
invitee
.
url
}
style=
{
{
position
:
'absolute'
,
right
:
-
1000
}
}
ref=
{
this
.
copyUrlRef
}
/>
<
i
className=
"fa fa-clipboard"
/>
Copy Invite
</
button
>
</
td
>
<
td
>
<
button
className=
"btn btn-danger btn-mini"
onClick=
{
()
=>
revokeInvite
(
invitee
.
code
)
}
>
<
i
className=
"fa fa-remove"
/>
</
button
>
</
td
>
</
tr
>
);
}
}
const
mapDispatchToProps
=
{
revokeInvite
,
};
export
default
connect
(()
=>
{
return
{};
},
mapDispatchToProps
)(
InviteeRow
);
public/app/features/users/InviteesTable.test.tsx
View file @
3581d619
...
@@ -7,7 +7,6 @@ import { getMockInvitees } from './__mocks__/userMocks';
...
@@ -7,7 +7,6 @@ import { getMockInvitees } from './__mocks__/userMocks';
const
setup
=
(
propOverrides
?:
object
)
=>
{
const
setup
=
(
propOverrides
?:
object
)
=>
{
const
props
:
Props
=
{
const
props
:
Props
=
{
invitees
:
[]
as
Invitee
[],
invitees
:
[]
as
Invitee
[],
onRevokeInvite
:
jest
.
fn
(),
};
};
Object
.
assign
(
props
,
propOverrides
);
Object
.
assign
(
props
,
propOverrides
);
...
...
public/app/features/users/InviteesTable.tsx
View file @
3581d619
import
React
,
{
createRef
,
PureComponent
}
from
'react'
;
import
React
,
{
PureComponent
}
from
'react'
;
import
{
Invitee
}
from
'app/types'
;
import
{
Invitee
}
from
'app/types'
;
import
InviteeRow
from
'./InviteeRow'
;
export
interface
Props
{
export
interface
Props
{
invitees
:
Invitee
[];
invitees
:
Invitee
[];
onRevokeInvite
:
(
code
:
string
)
=>
void
;
}
}
export
default
class
InviteesTable
extends
PureComponent
<
Props
>
{
export
default
class
InviteesTable
extends
PureComponent
<
Props
>
{
private
copyUrlRef
=
createRef
<
HTMLTextAreaElement
>
();
copyToClipboard
=
()
=>
{
const
node
=
this
.
copyUrlRef
.
current
;
if
(
node
)
{
node
.
select
();
document
.
execCommand
(
'copy'
);
}
};
render
()
{
render
()
{
const
{
invitees
,
onRevokeInvite
}
=
this
.
props
;
const
{
invitees
}
=
this
.
props
;
return
(
return
(
<
table
className=
"filter-table form-inline"
>
<
table
className=
"filter-table form-inline"
>
...
@@ -33,29 +22,7 @@ export default class InviteesTable extends PureComponent<Props> {
...
@@ -33,29 +22,7 @@ export default class InviteesTable extends PureComponent<Props> {
</
thead
>
</
thead
>
<
tbody
>
<
tbody
>
{
invitees
.
map
((
invitee
,
index
)
=>
{
{
invitees
.
map
((
invitee
,
index
)
=>
{
return
(
return
<
InviteeRow
key=
{
`${invitee.id}-${index}`
}
invitee=
{
invitee
}
/>;
<
tr
key=
{
`${invitee.id}-${index}`
}
>
<
td
>
{
invitee
.
email
}
</
td
>
<
td
>
{
invitee
.
name
}
</
td
>
<
td
className=
"text-right"
>
<
button
className=
"btn btn-inverse btn-mini"
onClick=
{
this
.
copyToClipboard
}
>
<
textarea
readOnly=
{
true
}
value=
{
invitee
.
url
}
style=
{
{
position
:
'absolute'
,
right
:
-
1000
}
}
ref=
{
this
.
copyUrlRef
}
/>
<
i
className=
"fa fa-clipboard"
/>
Copy Invite
</
button
>
</
td
>
<
td
>
<
button
className=
"btn btn-danger btn-mini"
onClick=
{
()
=>
onRevokeInvite
(
invitee
.
code
)
}
>
<
i
className=
"fa fa-remove"
/>
</
button
>
</
td
>
</
tr
>
);
})
}
})
}
</
tbody
>
</
tbody
>
</
table
>
</
table
>
...
...
public/app/features/users/UsersListPage.test.tsx
View file @
3581d619
...
@@ -16,7 +16,6 @@ const setup = (propOverrides?: object) => {
...
@@ -16,7 +16,6 @@ const setup = (propOverrides?: object) => {
invitees
:
[]
as
Invitee
[],
invitees
:
[]
as
Invitee
[],
searchQuery
:
''
,
searchQuery
:
''
,
externalUserMngInfo
:
''
,
externalUserMngInfo
:
''
,
revokeInvite
:
jest
.
fn
(),
loadInvitees
:
jest
.
fn
(),
loadInvitees
:
jest
.
fn
(),
loadUsers
:
jest
.
fn
(),
loadUsers
:
jest
.
fn
(),
updateUser
:
jest
.
fn
(),
updateUser
:
jest
.
fn
(),
...
...
public/app/features/users/UsersListPage.tsx
View file @
3581d619
...
@@ -9,7 +9,7 @@ import UsersTable from './UsersTable';
...
@@ -9,7 +9,7 @@ import UsersTable from './UsersTable';
import
InviteesTable
from
'./InviteesTable'
;
import
InviteesTable
from
'./InviteesTable'
;
import
{
Invitee
,
NavModel
,
OrgUser
}
from
'app/types'
;
import
{
Invitee
,
NavModel
,
OrgUser
}
from
'app/types'
;
import
appEvents
from
'app/core/app_events'
;
import
appEvents
from
'app/core/app_events'
;
import
{
loadUsers
,
loadInvitees
,
revokeInvite
,
setUsersSearchQuery
,
updateUser
,
removeUser
}
from
'./state/actions'
;
import
{
loadUsers
,
loadInvitees
,
setUsersSearchQuery
,
updateUser
,
removeUser
}
from
'./state/actions'
;
import
{
getNavModel
}
from
'../../core/selectors/navModel'
;
import
{
getNavModel
}
from
'../../core/selectors/navModel'
;
import
{
getInvitees
,
getUsers
,
getUsersSearchQuery
}
from
'./state/selectors'
;
import
{
getInvitees
,
getUsers
,
getUsersSearchQuery
}
from
'./state/selectors'
;
...
@@ -25,7 +25,6 @@ export interface Props {
...
@@ -25,7 +25,6 @@ export interface Props {
setUsersSearchQuery
:
typeof
setUsersSearchQuery
;
setUsersSearchQuery
:
typeof
setUsersSearchQuery
;
updateUser
:
typeof
updateUser
;
updateUser
:
typeof
updateUser
;
removeUser
:
typeof
removeUser
;
removeUser
:
typeof
removeUser
;
revokeInvite
:
typeof
revokeInvite
;
}
}
export
interface
State
{
export
interface
State
{
...
@@ -79,10 +78,6 @@ export class UsersListPage extends PureComponent<Props, State> {
...
@@ -79,10 +78,6 @@ export class UsersListPage extends PureComponent<Props, State> {
});
});
};
};
onRevokeInvite
=
code
=>
{
this
.
props
.
revokeInvite
(
code
);
};
onShowInvites
=
()
=>
{
onShowInvites
=
()
=>
{
this
.
setState
(
prevState
=>
({
this
.
setState
(
prevState
=>
({
showInvites
:
!
prevState
.
showInvites
,
showInvites
:
!
prevState
.
showInvites
,
...
@@ -93,7 +88,7 @@ export class UsersListPage extends PureComponent<Props, State> {
...
@@ -93,7 +88,7 @@ export class UsersListPage extends PureComponent<Props, State> {
const
{
invitees
,
users
}
=
this
.
props
;
const
{
invitees
,
users
}
=
this
.
props
;
if
(
this
.
state
.
showInvites
)
{
if
(
this
.
state
.
showInvites
)
{
return
<
InviteesTable
invitees=
{
invitees
}
onRevokeInvite=
{
code
=>
this
.
onRevokeInvite
(
code
)
}
/>;
return
<
InviteesTable
invitees=
{
invitees
}
/>;
}
else
{
}
else
{
return
(
return
(
<
UsersTable
<
UsersTable
...
@@ -141,7 +136,6 @@ const mapDispatchToProps = {
...
@@ -141,7 +136,6 @@ const mapDispatchToProps = {
setUsersSearchQuery
,
setUsersSearchQuery
,
updateUser
,
updateUser
,
removeUser
,
removeUser
,
revokeInvite
,
};
};
export
default
hot
(
module
)(
connect
(
mapStateToProps
,
mapDispatchToProps
)(
UsersListPage
));
export
default
hot
(
module
)(
connect
(
mapStateToProps
,
mapDispatchToProps
)(
UsersListPage
));
public/app/features/users/__mocks__/userMocks.ts
View file @
3581d619
...
@@ -48,7 +48,7 @@ export const getMockInvitees = (amount: number) => {
...
@@ -48,7 +48,7 @@ export const getMockInvitees = (amount: number) => {
orgId
:
1
,
orgId
:
1
,
role
:
'viewer'
,
role
:
'viewer'
,
status
:
'not accepted'
,
status
:
'not accepted'
,
url
:
`localhost/invite/$
$
{
i
}
`
,
url
:
`localhost/invite/
${
i
}
`
,
});
});
}
}
...
...
public/app/features/users/__snapshots__/InviteesTable.test.tsx.snap
View file @
3581d619
...
@@ -49,270 +49,132 @@ exports[`Render should render invitees 1`] = `
...
@@ -49,270 +49,132 @@ exports[`Render should render invitees 1`] = `
</tr>
</tr>
</thead>
</thead>
<tbody>
<tbody>
<tr
<Connect(InviteeRow)
invitee={
Object {
"code": "asdfasdfsadf-0",
"createdOn": "2018-10-02",
"email": "invitee-0@test.com",
"emailSent": true,
"emailSentOn": "2018-10-02",
"id": 0,
"invitedByEmail": "admin@grafana.com",
"invitedByLogin": "admin",
"invitedByName": "admin",
"name": "invitee-0",
"orgId": 1,
"role": "viewer",
"status": "not accepted",
"url": "localhost/invite/0",
}
}
key="0-0"
key="0-0"
>
/>
<td>
<Connect(InviteeRow)
invitee-0@test.com
invitee={
</td>
Object {
<td>
"code": "asdfasdfsadf-1",
invitee-0
"createdOn": "2018-10-02",
</td>
"email": "invitee-1@test.com",
<td
"emailSent": true,
className="text-right"
"emailSentOn": "2018-10-02",
>
"id": 1,
<button
"invitedByEmail": "admin@grafana.com",
className="btn btn-inverse btn-mini"
"invitedByLogin": "admin",
onClick={[Function]}
"invitedByName": "admin",
>
"name": "invitee-1",
<textarea
"orgId": 1,
readOnly={true}
"role": "viewer",
style={
"status": "not accepted",
Object {
"url": "localhost/invite/1",
"position": "absolute",
}
"right": -1000,
}
}
}
value="localhost/invite/$0"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
key="1-1"
key="1-1"
>
/>
<td>
<Connect(InviteeRow)
invitee-1@test.com
invitee={
</td>
Object {
<td>
"code": "asdfasdfsadf-2",
invitee-1
"createdOn": "2018-10-02",
</td>
"email": "invitee-2@test.com",
<td
"emailSent": true,
className="text-right"
"emailSentOn": "2018-10-02",
>
"id": 2,
<button
"invitedByEmail": "admin@grafana.com",
className="btn btn-inverse btn-mini"
"invitedByLogin": "admin",
onClick={[Function]}
"invitedByName": "admin",
>
"name": "invitee-2",
<textarea
"orgId": 1,
readOnly={true}
"role": "viewer",
style={
"status": "not accepted",
Object {
"url": "localhost/invite/2",
"position": "absolute",
}
"right": -1000,
}
}
}
value="localhost/invite/$1"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
key="2-2"
key="2-2"
>
/>
<td>
<Connect(InviteeRow)
invitee-2@test.com
invitee={
</td>
Object {
<td>
"code": "asdfasdfsadf-3",
invitee-2
"createdOn": "2018-10-02",
</td>
"email": "invitee-3@test.com",
<td
"emailSent": true,
className="text-right"
"emailSentOn": "2018-10-02",
>
"id": 3,
<button
"invitedByEmail": "admin@grafana.com",
className="btn btn-inverse btn-mini"
"invitedByLogin": "admin",
onClick={[Function]}
"invitedByName": "admin",
>
"name": "invitee-3",
<textarea
"orgId": 1,
readOnly={true}
"role": "viewer",
style={
"status": "not accepted",
Object {
"url": "localhost/invite/3",
"position": "absolute",
}
"right": -1000,
}
}
}
value="localhost/invite/$2"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
key="3-3"
key="3-3"
>
/>
<td>
<Connect(InviteeRow)
invitee-3@test.com
invitee={
</td>
Object {
<td>
"code": "asdfasdfsadf-4",
invitee-3
"createdOn": "2018-10-02",
</td>
"email": "invitee-4@test.com",
<td
"emailSent": true,
className="text-right"
"emailSentOn": "2018-10-02",
>
"id": 4,
<button
"invitedByEmail": "admin@grafana.com",
className="btn btn-inverse btn-mini"
"invitedByLogin": "admin",
onClick={[Function]}
"invitedByName": "admin",
>
"name": "invitee-4",
<textarea
"orgId": 1,
readOnly={true}
"role": "viewer",
style={
"status": "not accepted",
Object {
"url": "localhost/invite/4",
"position": "absolute",
}
"right": -1000,
}
}
}
value="localhost/invite/$3"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
key="4-4"
key="4-4"
>
/>
<td>
<Connect(InviteeRow)
invitee-4@test.com
invitee={
</td>
Object {
<td>
"code": "asdfasdfsadf-5",
invitee-4
"createdOn": "2018-10-02",
</td>
"email": "invitee-5@test.com",
<td
"emailSent": true,
className="text-right"
"emailSentOn": "2018-10-02",
>
"id": 5,
<button
"invitedByEmail": "admin@grafana.com",
className="btn btn-inverse btn-mini"
"invitedByLogin": "admin",
onClick={[Function]}
"invitedByName": "admin",
>
"name": "invitee-5",
<textarea
"orgId": 1,
readOnly={true}
"role": "viewer",
style={
"status": "not accepted",
Object {
"url": "localhost/invite/5",
"position": "absolute",
}
"right": -1000,
}
}
}
value="localhost/invite/$4"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
key="5-5"
key="5-5"
>
/>
<td>
invitee-5@test.com
</td>
<td>
invitee-5
</td>
<td
className="text-right"
>
<button
className="btn btn-inverse btn-mini"
onClick={[Function]}
>
<textarea
readOnly={true}
style={
Object {
"position": "absolute",
"right": -1000,
}
}
value="localhost/invite/$5"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
</tbody>
</tbody>
</table>
</table>
`;
`;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment