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
02e7d713
Commit
02e7d713
authored
Oct 11, 2018
by
Peter Holmberg
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added Loading state on org pages
parent
974eddee
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
244 additions
and
166 deletions
+244
-166
public/app/core/components/PageLoader/PageLoader.tsx
+17
-0
public/app/features/api-keys/ApiKeysPage.test.tsx
+2
-0
public/app/features/api-keys/ApiKeysPage.tsx
+41
-29
public/app/features/api-keys/__snapshots__/ApiKeysPage.test.tsx.snap
+5
-26
public/app/features/api-keys/state/reducers.ts
+2
-1
public/app/features/api-keys/state/selectors.test.ts
+2
-2
public/app/features/datasources/DataSourcesListPage.test.tsx
+2
-0
public/app/features/datasources/DataSourcesListPage.tsx
+9
-6
public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap
+2
-13
public/app/features/datasources/state/reducers.ts
+2
-1
public/app/features/plugins/PluginListPage.test.tsx
+11
-8
public/app/features/plugins/PluginListPage.tsx
+18
-2
public/app/features/plugins/__snapshots__/PluginListPage.test.tsx.snap
+27
-0
public/app/features/plugins/state/reducers.ts
+2
-1
public/app/features/teams/TeamList.test.tsx
+2
-0
public/app/features/teams/TeamList.tsx
+15
-2
public/app/features/teams/__snapshots__/TeamList.test.tsx.snap
+3
-18
public/app/features/teams/state/reducers.ts
+2
-2
public/app/features/teams/state/selectors.test.ts
+2
-2
public/app/features/users/UsersListPage.test.tsx
+9
-0
public/app/features/users/UsersListPage.tsx
+22
-11
public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap
+20
-1
public/app/features/users/state/reducers.ts
+4
-3
public/app/types/apiKeys.ts
+1
-0
public/app/types/datasources.ts
+1
-0
public/app/types/plugins.ts
+1
-0
public/app/types/teams.ts
+1
-0
public/app/types/user.ts
+1
-0
public/app/types/users.ts
+0
-37
public/sass/_grafana.scss
+2
-1
public/sass/components/_page_loader.scss
+16
-0
No files found.
public/app/core/components/PageLoader/PageLoader.tsx
0 → 100644
View file @
02e7d713
import
React
,
{
SFC
}
from
'react'
;
interface
Props
{
pageName
:
string
;
}
const
PageLoader
:
SFC
<
Props
>
=
({
pageName
})
=>
{
const
loadingText
=
`Loading
${
pageName
}
...`
;
return
(
<
div
className=
"page-loader-wrapper"
>
<
i
className=
"page-loader-wrapper__spinner fa fa-spinner fa-spin"
/>
<
div
className=
"page-loader-wrapper__text"
>
{
loadingText
}
</
div
>
</
div
>
);
};
export
default
PageLoader
;
public/app/features/api-keys/ApiKeysPage.test.tsx
View file @
02e7d713
...
@@ -9,6 +9,7 @@ const setup = (propOverrides?: object) => {
...
@@ -9,6 +9,7 @@ const setup = (propOverrides?: object) => {
navModel
:
{}
as
NavModel
,
navModel
:
{}
as
NavModel
,
apiKeys
:
[]
as
ApiKey
[],
apiKeys
:
[]
as
ApiKey
[],
searchQuery
:
''
,
searchQuery
:
''
,
hasFetched
:
false
,
loadApiKeys
:
jest
.
fn
(),
loadApiKeys
:
jest
.
fn
(),
deleteApiKey
:
jest
.
fn
(),
deleteApiKey
:
jest
.
fn
(),
setSearchQuery
:
jest
.
fn
(),
setSearchQuery
:
jest
.
fn
(),
...
@@ -35,6 +36,7 @@ describe('Render', () => {
...
@@ -35,6 +36,7 @@ describe('Render', () => {
it
(
'should render API keys table'
,
()
=>
{
it
(
'should render API keys table'
,
()
=>
{
const
{
wrapper
}
=
setup
({
const
{
wrapper
}
=
setup
({
apiKeys
:
getMultipleMockKeys
(
5
),
apiKeys
:
getMultipleMockKeys
(
5
),
hasFetched
:
true
,
});
});
expect
(
wrapper
).
toMatchSnapshot
();
expect
(
wrapper
).
toMatchSnapshot
();
...
...
public/app/features/api-keys/ApiKeysPage.tsx
View file @
02e7d713
...
@@ -8,6 +8,7 @@ import { getApiKeys } from './state/selectors';
...
@@ -8,6 +8,7 @@ import { getApiKeys } from './state/selectors';
import
{
loadApiKeys
,
deleteApiKey
,
setSearchQuery
,
addApiKey
}
from
'./state/actions'
;
import
{
loadApiKeys
,
deleteApiKey
,
setSearchQuery
,
addApiKey
}
from
'./state/actions'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
SlideDown
from
'app/core/components/Animations/SlideDown'
;
import
SlideDown
from
'app/core/components/Animations/SlideDown'
;
import
PageLoader
from
'app/core/components/PageLoader/PageLoader'
;
import
ApiKeysAddedModal
from
'./ApiKeysAddedModal'
;
import
ApiKeysAddedModal
from
'./ApiKeysAddedModal'
;
import
config
from
'app/core/config'
;
import
config
from
'app/core/config'
;
import
appEvents
from
'app/core/app_events'
;
import
appEvents
from
'app/core/app_events'
;
...
@@ -16,6 +17,7 @@ export interface Props {
...
@@ -16,6 +17,7 @@ export interface Props {
navModel
:
NavModel
;
navModel
:
NavModel
;
apiKeys
:
ApiKey
[];
apiKeys
:
ApiKey
[];
searchQuery
:
string
;
searchQuery
:
string
;
hasFetched
:
boolean
;
loadApiKeys
:
typeof
loadApiKeys
;
loadApiKeys
:
typeof
loadApiKeys
;
deleteApiKey
:
typeof
deleteApiKey
;
deleteApiKey
:
typeof
deleteApiKey
;
setSearchQuery
:
typeof
setSearchQuery
;
setSearchQuery
:
typeof
setSearchQuery
;
...
@@ -99,9 +101,45 @@ export class ApiKeysPage extends PureComponent<Props, any> {
...
@@ -99,9 +101,45 @@ export class ApiKeysPage extends PureComponent<Props, any> {
});
});
};
};
renderTable
()
{
const
{
apiKeys
}
=
this
.
props
;
return
[
<
h3
key=
"header"
className=
"page-heading"
>
Existing Keys
</
h3
>,
<
table
key=
"table"
className=
"filter-table"
>
<
thead
>
<
tr
>
<
th
>
Name
</
th
>
<
th
>
Role
</
th
>
<
th
style=
{
{
width
:
'34px'
}
}
/>
</
tr
>
</
thead
>
{
apiKeys
.
length
>
0
&&
(
<
tbody
>
{
apiKeys
.
map
(
key
=>
{
return
(
<
tr
key=
{
key
.
id
}
>
<
td
>
{
key
.
name
}
</
td
>
<
td
>
{
key
.
role
}
</
td
>
<
td
>
<
a
onClick=
{
()
=>
this
.
onDeleteApiKey
(
key
)
}
className=
"btn btn-danger btn-mini"
>
<
i
className=
"fa fa-remove"
/>
</
a
>
</
td
>
</
tr
>
);
})
}
</
tbody
>
)
}
</
table
>,
];
}
render
()
{
render
()
{
const
{
newApiKey
,
isAdding
}
=
this
.
state
;
const
{
newApiKey
,
isAdding
}
=
this
.
state
;
const
{
navModel
,
apiKeys
,
searchQuery
}
=
this
.
props
;
const
{
hasFetched
,
navModel
,
searchQuery
}
=
this
.
props
;
return
(
return
(
<
div
>
<
div
>
...
@@ -170,34 +208,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
...
@@ -170,34 +208,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
</
form
>
</
form
>
</
div
>
</
div
>
</
SlideDown
>
</
SlideDown
>
{
hasFetched
?
this
.
renderTable
()
:
<
PageLoader
pageName=
"Api keys"
/>
}
<
h3
className=
"page-heading"
>
Existing Keys
</
h3
>
<
table
className=
"filter-table"
>
<
thead
>
<
tr
>
<
th
>
Name
</
th
>
<
th
>
Role
</
th
>
<
th
style=
{
{
width
:
'34px'
}
}
/>
</
tr
>
</
thead
>
{
apiKeys
.
length
>
0
?
(
<
tbody
>
{
apiKeys
.
map
(
key
=>
{
return
(
<
tr
key=
{
key
.
id
}
>
<
td
>
{
key
.
name
}
</
td
>
<
td
>
{
key
.
role
}
</
td
>
<
td
>
<
a
onClick=
{
()
=>
this
.
onDeleteApiKey
(
key
)
}
className=
"btn btn-danger btn-mini"
>
<
i
className=
"fa fa-remove"
/>
</
a
>
</
td
>
</
tr
>
);
})
}
</
tbody
>
)
:
null
}
</
table
>
</
div
>
</
div
>
</
div
>
</
div
>
);
);
...
@@ -209,6 +220,7 @@ function mapStateToProps(state) {
...
@@ -209,6 +220,7 @@ function mapStateToProps(state) {
navModel
:
getNavModel
(
state
.
navIndex
,
'apikeys'
),
navModel
:
getNavModel
(
state
.
navIndex
,
'apikeys'
),
apiKeys
:
getApiKeys
(
state
.
apiKeys
),
apiKeys
:
getApiKeys
(
state
.
apiKeys
),
searchQuery
:
state
.
apiKeys
.
searchQuery
,
searchQuery
:
state
.
apiKeys
.
searchQuery
,
hasFetched
:
state
.
apiKeys
.
hasFetched
,
};
};
}
}
...
...
public/app/features/api-keys/__snapshots__/ApiKeysPage.test.tsx.snap
View file @
02e7d713
...
@@ -138,11 +138,13 @@ exports[`Render should render API keys table 1`] = `
...
@@ -138,11 +138,13 @@ exports[`Render should render API keys table 1`] = `
</Component>
</Component>
<h3
<h3
className="page-heading"
className="page-heading"
key="header"
>
>
Existing Keys
Existing Keys
</h3>
</h3>
<table
<table
className="filter-table"
className="filter-table"
key="table"
>
>
<thead>
<thead>
<tr>
<tr>
...
@@ -404,32 +406,9 @@ exports[`Render should render component 1`] = `
...
@@ -404,32 +406,9 @@ exports[`Render should render component 1`] = `
</form>
</form>
</div>
</div>
</Component>
</Component>
<h3
<PageLoader
className="page-heading"
pageName="Api keys"
>
/>
Existing Keys
</h3>
<table
className="filter-table"
>
<thead>
<tr>
<th>
Name
</th>
<th>
Role
</th>
<th
style={
Object {
"width": "34px",
}
}
/>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
`;
`;
public/app/features/api-keys/state/reducers.ts
View file @
02e7d713
...
@@ -4,12 +4,13 @@ import { Action, ActionTypes } from './actions';
...
@@ -4,12 +4,13 @@ import { Action, ActionTypes } from './actions';
export
const
initialApiKeysState
:
ApiKeysState
=
{
export
const
initialApiKeysState
:
ApiKeysState
=
{
keys
:
[],
keys
:
[],
searchQuery
:
''
,
searchQuery
:
''
,
hasFetched
:
false
,
};
};
export
const
apiKeysReducer
=
(
state
=
initialApiKeysState
,
action
:
Action
):
ApiKeysState
=>
{
export
const
apiKeysReducer
=
(
state
=
initialApiKeysState
,
action
:
Action
):
ApiKeysState
=>
{
switch
(
action
.
type
)
{
switch
(
action
.
type
)
{
case
ActionTypes
.
LoadApiKeys
:
case
ActionTypes
.
LoadApiKeys
:
return
{
...
state
,
keys
:
action
.
payload
};
return
{
...
state
,
hasFetched
:
true
,
keys
:
action
.
payload
};
case
ActionTypes
.
SetApiKeysSearchQuery
:
case
ActionTypes
.
SetApiKeysSearchQuery
:
return
{
...
state
,
searchQuery
:
action
.
payload
};
return
{
...
state
,
searchQuery
:
action
.
payload
};
}
}
...
...
public/app/features/api-keys/state/selectors.test.ts
View file @
02e7d713
...
@@ -7,7 +7,7 @@ describe('API Keys selectors', () => {
...
@@ -7,7 +7,7 @@ describe('API Keys selectors', () => {
const
mockKeys
=
getMultipleMockKeys
(
5
);
const
mockKeys
=
getMultipleMockKeys
(
5
);
it
(
'should return all keys if no search query'
,
()
=>
{
it
(
'should return all keys if no search query'
,
()
=>
{
const
mockState
:
ApiKeysState
=
{
keys
:
mockKeys
,
searchQuery
:
''
};
const
mockState
:
ApiKeysState
=
{
keys
:
mockKeys
,
searchQuery
:
''
,
hasFetched
:
false
};
const
keys
=
getApiKeys
(
mockState
);
const
keys
=
getApiKeys
(
mockState
);
...
@@ -15,7 +15,7 @@ describe('API Keys selectors', () => {
...
@@ -15,7 +15,7 @@ describe('API Keys selectors', () => {
});
});
it
(
'should filter keys if search query exists'
,
()
=>
{
it
(
'should filter keys if search query exists'
,
()
=>
{
const
mockState
:
ApiKeysState
=
{
keys
:
mockKeys
,
searchQuery
:
'5'
};
const
mockState
:
ApiKeysState
=
{
keys
:
mockKeys
,
searchQuery
:
'5'
,
hasFetched
:
false
};
const
keys
=
getApiKeys
(
mockState
);
const
keys
=
getApiKeys
(
mockState
);
...
...
public/app/features/datasources/DataSourcesListPage.test.tsx
View file @
02e7d713
...
@@ -15,6 +15,7 @@ const setup = (propOverrides?: object) => {
...
@@ -15,6 +15,7 @@ const setup = (propOverrides?: object) => {
searchQuery
:
''
,
searchQuery
:
''
,
setDataSourcesSearchQuery
:
jest
.
fn
(),
setDataSourcesSearchQuery
:
jest
.
fn
(),
setDataSourcesLayoutMode
:
jest
.
fn
(),
setDataSourcesLayoutMode
:
jest
.
fn
(),
hasFetched
:
false
,
};
};
Object
.
assign
(
props
,
propOverrides
);
Object
.
assign
(
props
,
propOverrides
);
...
@@ -33,6 +34,7 @@ describe('Render', () => {
...
@@ -33,6 +34,7 @@ describe('Render', () => {
const
wrapper
=
setup
({
const
wrapper
=
setup
({
dataSources
:
getMockDataSources
(
5
),
dataSources
:
getMockDataSources
(
5
),
dataSourcesCount
:
5
,
dataSourcesCount
:
5
,
hasFetched
:
true
,
});
});
expect
(
wrapper
).
toMatchSnapshot
();
expect
(
wrapper
).
toMatchSnapshot
();
...
...
public/app/features/datasources/DataSourcesListPage.tsx
View file @
02e7d713
...
@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
...
@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
import
{
connect
}
from
'react-redux'
;
import
{
connect
}
from
'react-redux'
;
import
{
hot
}
from
'react-hot-loader'
;
import
{
hot
}
from
'react-hot-loader'
;
import
PageHeader
from
'../../core/components/PageHeader/PageHeader'
;
import
PageHeader
from
'../../core/components/PageHeader/PageHeader'
;
import
PageLoader
from
'app/core/components/PageLoader/PageLoader'
;
import
OrgActionBar
from
'../../core/components/OrgActionBar/OrgActionBar'
;
import
OrgActionBar
from
'../../core/components/OrgActionBar/OrgActionBar'
;
import
EmptyListCTA
from
'../../core/components/EmptyListCTA/EmptyListCTA'
;
import
EmptyListCTA
from
'../../core/components/EmptyListCTA/EmptyListCTA'
;
import
DataSourcesList
from
'./DataSourcesList'
;
import
DataSourcesList
from
'./DataSourcesList'
;
...
@@ -22,6 +23,7 @@ export interface Props {
...
@@ -22,6 +23,7 @@ export interface Props {
dataSourcesCount
:
number
;
dataSourcesCount
:
number
;
layoutMode
:
LayoutMode
;
layoutMode
:
LayoutMode
;
searchQuery
:
string
;
searchQuery
:
string
;
hasFetched
:
boolean
;
loadDataSources
:
typeof
loadDataSources
;
loadDataSources
:
typeof
loadDataSources
;
setDataSourcesLayoutMode
:
typeof
setDataSourcesLayoutMode
;
setDataSourcesLayoutMode
:
typeof
setDataSourcesLayoutMode
;
setDataSourcesSearchQuery
:
typeof
setDataSourcesSearchQuery
;
setDataSourcesSearchQuery
:
typeof
setDataSourcesSearchQuery
;
...
@@ -56,6 +58,7 @@ export class DataSourcesListPage extends PureComponent<Props> {
...
@@ -56,6 +58,7 @@ export class DataSourcesListPage extends PureComponent<Props> {
searchQuery
,
searchQuery
,
setDataSourcesSearchQuery
,
setDataSourcesSearchQuery
,
setDataSourcesLayoutMode
,
setDataSourcesLayoutMode
,
hasFetched
,
}
=
this
.
props
;
}
=
this
.
props
;
const
linkButton
=
{
const
linkButton
=
{
...
@@ -67,10 +70,10 @@ export class DataSourcesListPage extends PureComponent<Props> {
...
@@ -67,10 +70,10 @@ export class DataSourcesListPage extends PureComponent<Props> {
<
div
>
<
div
>
<
PageHeader
model=
{
navModel
}
/>
<
PageHeader
model=
{
navModel
}
/>
<
div
className=
"page-container page-body"
>
<
div
className=
"page-container page-body"
>
{
dataSourcesCount
===
0
?
(
{
!
hasFetched
&&
<
PageLoader
pageName=
"Data sources"
/>
}
<
EmptyListCTA
model=
{
emptyListModel
}
/>
{
hasFetched
&&
dataSourcesCount
===
0
&&
<
EmptyListCTA
model=
{
emptyListModel
}
/>
}
)
:
(
{
hasFetched
&&
[
dataSourcesCount
>
0
&&
[
<
OrgActionBar
<
OrgActionBar
layoutMode=
{
layoutMode
}
layoutMode=
{
layoutMode
}
searchQuery=
{
searchQuery
}
searchQuery=
{
searchQuery
}
...
@@ -80,8 +83,7 @@ export class DataSourcesListPage extends PureComponent<Props> {
...
@@ -80,8 +83,7 @@ export class DataSourcesListPage extends PureComponent<Props> {
key=
"action-bar"
key=
"action-bar"
/>,
/>,
<
DataSourcesList
dataSources=
{
dataSources
}
layoutMode=
{
layoutMode
}
key=
"list"
/>,
<
DataSourcesList
dataSources=
{
dataSources
}
layoutMode=
{
layoutMode
}
key=
"list"
/>,
]
]
}
)
}
</
div
>
</
div
>
</
div
>
</
div
>
);
);
...
@@ -95,6 +97,7 @@ function mapStateToProps(state) {
...
@@ -95,6 +97,7 @@ function mapStateToProps(state) {
layoutMode
:
getDataSourcesLayoutMode
(
state
.
dataSources
),
layoutMode
:
getDataSourcesLayoutMode
(
state
.
dataSources
),
dataSourcesCount
:
getDataSourcesCount
(
state
.
dataSources
),
dataSourcesCount
:
getDataSourcesCount
(
state
.
dataSources
),
searchQuery
:
getDataSourcesSearchQuery
(
state
.
dataSources
),
searchQuery
:
getDataSourcesSearchQuery
(
state
.
dataSources
),
hasFetched
:
state
.
dataSources
.
hasFetched
,
};
};
}
}
...
...
public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap
View file @
02e7d713
...
@@ -155,19 +155,8 @@ exports[`Render should render component 1`] = `
...
@@ -155,19 +155,8 @@ exports[`Render should render component 1`] = `
<div
<div
className="page-container page-body"
className="page-container page-body"
>
>
<EmptyListCTA
<PageLoader
model={
pageName="Data sources"
Object {
"buttonIcon": "gicon gicon-add-datasources",
"buttonLink": "datasources/new",
"buttonTitle": "Add data source",
"proTip": "You can also define data sources through configuration files.",
"proTipLink": "http://docs.grafana.org/administration/provisioning/#datasources?utm_source=grafana_ds_list",
"proTipLinkTitle": "Learn more",
"proTipTarget": "_blank",
"title": "There are no data sources defined yet",
}
}
/>
/>
</div>
</div>
</div>
</div>
...
...
public/app/features/datasources/state/reducers.ts
View file @
02e7d713
...
@@ -9,12 +9,13 @@ const initialState: DataSourcesState = {
...
@@ -9,12 +9,13 @@ const initialState: DataSourcesState = {
dataSourcesCount
:
0
,
dataSourcesCount
:
0
,
dataSourceTypes
:
[]
as
Plugin
[],
dataSourceTypes
:
[]
as
Plugin
[],
dataSourceTypeSearchQuery
:
''
,
dataSourceTypeSearchQuery
:
''
,
hasFetched
:
false
,
};
};
export
const
dataSourcesReducer
=
(
state
=
initialState
,
action
:
Action
):
DataSourcesState
=>
{
export
const
dataSourcesReducer
=
(
state
=
initialState
,
action
:
Action
):
DataSourcesState
=>
{
switch
(
action
.
type
)
{
switch
(
action
.
type
)
{
case
ActionTypes
.
LoadDataSources
:
case
ActionTypes
.
LoadDataSources
:
return
{
...
state
,
dataSources
:
action
.
payload
,
dataSourcesCount
:
action
.
payload
.
length
};
return
{
...
state
,
hasFetched
:
true
,
dataSources
:
action
.
payload
,
dataSourcesCount
:
action
.
payload
.
length
};
case
ActionTypes
.
SetDataSourcesSearchQuery
:
case
ActionTypes
.
SetDataSourcesSearchQuery
:
return
{
...
state
,
searchQuery
:
action
.
payload
};
return
{
...
state
,
searchQuery
:
action
.
payload
};
...
...
public/app/features/plugins/PluginListPage.test.tsx
View file @
02e7d713
...
@@ -13,22 +13,25 @@ const setup = (propOverrides?: object) => {
...
@@ -13,22 +13,25 @@ const setup = (propOverrides?: object) => {
setPluginsLayoutMode
:
jest
.
fn
(),
setPluginsLayoutMode
:
jest
.
fn
(),
layoutMode
:
LayoutModes
.
Grid
,
layoutMode
:
LayoutModes
.
Grid
,
loadPlugins
:
jest
.
fn
(),
loadPlugins
:
jest
.
fn
(),
hasFetched
:
false
,
};
};
Object
.
assign
(
props
,
propOverrides
);
Object
.
assign
(
props
,
propOverrides
);
const
wrapper
=
shallow
(<
PluginListPage
{
...
props
}
/>);
return
shallow
(<
PluginListPage
{
...
props
}
/>);
const
instance
=
wrapper
.
instance
()
as
PluginListPage
;
return
{
wrapper
,
instance
,
};
};
};
describe
(
'Render'
,
()
=>
{
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
{
wrapper
}
=
setup
();
const
wrapper
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render list'
,
()
=>
{
const
wrapper
=
setup
({
hasFetched
:
true
,
});
expect
(
wrapper
).
toMatchSnapshot
();
expect
(
wrapper
).
toMatchSnapshot
();
});
});
...
...
public/app/features/plugins/PluginListPage.tsx
View file @
02e7d713
...
@@ -3,6 +3,7 @@ import { hot } from 'react-hot-loader';
...
@@ -3,6 +3,7 @@ import { hot } from 'react-hot-loader';
import
{
connect
}
from
'react-redux'
;
import
{
connect
}
from
'react-redux'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
OrgActionBar
from
'app/core/components/OrgActionBar/OrgActionBar'
;
import
OrgActionBar
from
'app/core/components/OrgActionBar/OrgActionBar'
;
import
PageLoader
from
'app/core/components/PageLoader/PageLoader'
;
import
PluginList
from
'./PluginList'
;
import
PluginList
from
'./PluginList'
;
import
{
NavModel
,
Plugin
}
from
'app/types'
;
import
{
NavModel
,
Plugin
}
from
'app/types'
;
import
{
loadPlugins
,
setPluginsLayoutMode
,
setPluginsSearchQuery
}
from
'./state/actions'
;
import
{
loadPlugins
,
setPluginsLayoutMode
,
setPluginsSearchQuery
}
from
'./state/actions'
;
...
@@ -15,6 +16,7 @@ export interface Props {
...
@@ -15,6 +16,7 @@ export interface Props {
plugins
:
Plugin
[];
plugins
:
Plugin
[];
layoutMode
:
LayoutMode
;
layoutMode
:
LayoutMode
;
searchQuery
:
string
;
searchQuery
:
string
;
hasFetched
:
boolean
;
loadPlugins
:
typeof
loadPlugins
;
loadPlugins
:
typeof
loadPlugins
;
setPluginsLayoutMode
:
typeof
setPluginsLayoutMode
;
setPluginsLayoutMode
:
typeof
setPluginsLayoutMode
;
setPluginsSearchQuery
:
typeof
setPluginsSearchQuery
;
setPluginsSearchQuery
:
typeof
setPluginsSearchQuery
;
...
@@ -30,12 +32,21 @@ export class PluginListPage extends PureComponent<Props> {
...
@@ -30,12 +32,21 @@ export class PluginListPage extends PureComponent<Props> {
}
}
render
()
{
render
()
{
const
{
navModel
,
plugins
,
layoutMode
,
setPluginsLayoutMode
,
setPluginsSearchQuery
,
searchQuery
}
=
this
.
props
;
const
{
hasFetched
,
navModel
,
plugins
,
layoutMode
,
setPluginsLayoutMode
,
setPluginsSearchQuery
,
searchQuery
,
}
=
this
.
props
;
const
linkButton
=
{
const
linkButton
=
{
href
:
'https://grafana.com/plugins?utm_source=grafana_plugin_list'
,
href
:
'https://grafana.com/plugins?utm_source=grafana_plugin_list'
,
title
:
'Find more plugins on Grafana.com'
,
title
:
'Find more plugins on Grafana.com'
,
};
};
return
(
return
(
<
div
>
<
div
>
<
PageHeader
model=
{
navModel
}
/>
<
PageHeader
model=
{
navModel
}
/>
...
@@ -47,7 +58,11 @@ export class PluginListPage extends PureComponent<Props> {
...
@@ -47,7 +58,11 @@ export class PluginListPage extends PureComponent<Props> {
setSearchQuery=
{
query
=>
setPluginsSearchQuery
(
query
)
}
setSearchQuery=
{
query
=>
setPluginsSearchQuery
(
query
)
}
linkButton=
{
linkButton
}
linkButton=
{
linkButton
}
/>
/>
{
plugins
&&
<
PluginList
plugins=
{
plugins
}
layoutMode=
{
layoutMode
}
/>
}
{
hasFetched
?
(
plugins
&&
<
PluginList
plugins=
{
plugins
}
layoutMode=
{
layoutMode
}
/>
)
:
(
<
PageLoader
pageName=
"Plugins"
/>
)
}
</
div
>
</
div
>
</
div
>
</
div
>
);
);
...
@@ -60,6 +75,7 @@ function mapStateToProps(state) {
...
@@ -60,6 +75,7 @@ function mapStateToProps(state) {
plugins
:
getPlugins
(
state
.
plugins
),
plugins
:
getPlugins
(
state
.
plugins
),
layoutMode
:
getLayoutMode
(
state
.
plugins
),
layoutMode
:
getLayoutMode
(
state
.
plugins
),
searchQuery
:
getPluginsSearchQuery
(
state
.
plugins
),
searchQuery
:
getPluginsSearchQuery
(
state
.
plugins
),
hasFetched
:
state
.
plugins
.
hasFetched
,
};
};
}
}
...
...
public/app/features/plugins/__snapshots__/PluginListPage.test.tsx.snap
View file @
02e7d713
...
@@ -20,6 +20,33 @@ exports[`Render should render component 1`] = `
...
@@ -20,6 +20,33 @@ exports[`Render should render component 1`] = `
searchQuery=""
searchQuery=""
setSearchQuery={[Function]}
setSearchQuery={[Function]}
/>
/>
<PageLoader
pageName="Plugins"
/>
</div>
</div>
`;
exports[`Render should render list 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<OrgActionBar
layoutMode="grid"
linkButton={
Object {
"href": "https://grafana.com/plugins?utm_source=grafana_plugin_list",
"title": "Find more plugins on Grafana.com",
}
}
onSetLayoutMode={[Function]}
searchQuery=""
setSearchQuery={[Function]}
/>
<PluginList
<PluginList
layoutMode="grid"
layoutMode="grid"
plugins={Array []}
plugins={Array []}
...
...
public/app/features/plugins/state/reducers.ts
View file @
02e7d713
...
@@ -6,12 +6,13 @@ export const initialState: PluginsState = {
...
@@ -6,12 +6,13 @@ export const initialState: PluginsState = {
plugins
:
[]
as
Plugin
[],
plugins
:
[]
as
Plugin
[],
searchQuery
:
''
,
searchQuery
:
''
,
layoutMode
:
LayoutModes
.
Grid
,
layoutMode
:
LayoutModes
.
Grid
,
hasFetched
:
false
,
};
};
export
const
pluginsReducer
=
(
state
=
initialState
,
action
:
Action
):
PluginsState
=>
{
export
const
pluginsReducer
=
(
state
=
initialState
,
action
:
Action
):
PluginsState
=>
{
switch
(
action
.
type
)
{
switch
(
action
.
type
)
{
case
ActionTypes
.
LoadPlugins
:
case
ActionTypes
.
LoadPlugins
:
return
{
...
state
,
plugins
:
action
.
payload
};
return
{
...
state
,
hasFetched
:
true
,
plugins
:
action
.
payload
};
case
ActionTypes
.
SetPluginsSearchQuery
:
case
ActionTypes
.
SetPluginsSearchQuery
:
return
{
...
state
,
searchQuery
:
action
.
payload
};
return
{
...
state
,
searchQuery
:
action
.
payload
};
...
...
public/app/features/teams/TeamList.test.tsx
View file @
02e7d713
...
@@ -13,6 +13,7 @@ const setup = (propOverrides?: object) => {
...
@@ -13,6 +13,7 @@ const setup = (propOverrides?: object) => {
setSearchQuery
:
jest
.
fn
(),
setSearchQuery
:
jest
.
fn
(),
searchQuery
:
''
,
searchQuery
:
''
,
teamsCount
:
0
,
teamsCount
:
0
,
hasFetched
:
false
,
};
};
Object
.
assign
(
props
,
propOverrides
);
Object
.
assign
(
props
,
propOverrides
);
...
@@ -36,6 +37,7 @@ describe('Render', () => {
...
@@ -36,6 +37,7 @@ describe('Render', () => {
const
{
wrapper
}
=
setup
({
const
{
wrapper
}
=
setup
({
teams
:
getMultipleMockTeams
(
5
),
teams
:
getMultipleMockTeams
(
5
),
teamsCount
:
5
,
teamsCount
:
5
,
hasFetched
:
true
,
});
});
expect
(
wrapper
).
toMatchSnapshot
();
expect
(
wrapper
).
toMatchSnapshot
();
...
...
public/app/features/teams/TeamList.tsx
View file @
02e7d713
...
@@ -4,6 +4,7 @@ import { hot } from 'react-hot-loader';
...
@@ -4,6 +4,7 @@ import { hot } from 'react-hot-loader';
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
DeleteButton
from
'app/core/components/DeleteButton/DeleteButton'
;
import
DeleteButton
from
'app/core/components/DeleteButton/DeleteButton'
;
import
EmptyListCTA
from
'app/core/components/EmptyListCTA/EmptyListCTA'
;
import
EmptyListCTA
from
'app/core/components/EmptyListCTA/EmptyListCTA'
;
import
PageLoader
from
'app/core/components/PageLoader/PageLoader'
;
import
{
NavModel
,
Team
}
from
'../../types'
;
import
{
NavModel
,
Team
}
from
'../../types'
;
import
{
loadTeams
,
deleteTeam
,
setSearchQuery
}
from
'./state/actions'
;
import
{
loadTeams
,
deleteTeam
,
setSearchQuery
}
from
'./state/actions'
;
import
{
getSearchQuery
,
getTeams
,
getTeamsCount
}
from
'./state/selectors'
;
import
{
getSearchQuery
,
getTeams
,
getTeamsCount
}
from
'./state/selectors'
;
...
@@ -14,6 +15,7 @@ export interface Props {
...
@@ -14,6 +15,7 @@ export interface Props {
teams
:
Team
[];
teams
:
Team
[];
searchQuery
:
string
;
searchQuery
:
string
;
teamsCount
:
number
;
teamsCount
:
number
;
hasFetched
:
boolean
;
loadTeams
:
typeof
loadTeams
;
loadTeams
:
typeof
loadTeams
;
deleteTeam
:
typeof
deleteTeam
;
deleteTeam
:
typeof
deleteTeam
;
setSearchQuery
:
typeof
setSearchQuery
;
setSearchQuery
:
typeof
setSearchQuery
;
...
@@ -125,13 +127,23 @@ export class TeamList extends PureComponent<Props, any> {
...
@@ -125,13 +127,23 @@ export class TeamList extends PureComponent<Props, any> {
);
);
}
}
renderList
()
{
const
{
teamsCount
}
=
this
.
props
;
if
(
teamsCount
>
0
)
{
return
this
.
renderTeamList
();
}
else
{
return
this
.
renderEmptyList
();
}
}
render
()
{
render
()
{
const
{
navModel
,
teamsCount
}
=
this
.
props
;
const
{
hasFetched
,
navModel
}
=
this
.
props
;
return
(
return
(
<
div
>
<
div
>
<
PageHeader
model=
{
navModel
}
/>
<
PageHeader
model=
{
navModel
}
/>
{
teamsCount
>
0
?
this
.
renderTeamList
()
:
this
.
renderEmptyList
()
}
{
hasFetched
?
this
.
renderList
()
:
<
PageLoader
pageName=
"Teams"
/>
}
</
div
>
</
div
>
);
);
}
}
...
@@ -143,6 +155,7 @@ function mapStateToProps(state) {
...
@@ -143,6 +155,7 @@ function mapStateToProps(state) {
teams
:
getTeams
(
state
.
teams
),
teams
:
getTeams
(
state
.
teams
),
searchQuery
:
getSearchQuery
(
state
.
teams
),
searchQuery
:
getSearchQuery
(
state
.
teams
),
teamsCount
:
getTeamsCount
(
state
.
teams
),
teamsCount
:
getTeamsCount
(
state
.
teams
),
hasFetched
:
state
.
teams
.
hasFetched
,
};
};
}
}
...
...
public/app/features/teams/__snapshots__/TeamList.test.tsx.snap
View file @
02e7d713
...
@@ -5,24 +5,9 @@ exports[`Render should render component 1`] = `
...
@@ -5,24 +5,9 @@ exports[`Render should render component 1`] = `
<PageHeader
<PageHeader
model={Object {}}
model={Object {}}
/>
/>
<div
<PageLoader
className="page-container page-body"
pageName="Teams"
>
/>
<EmptyListCTA
model={
Object {
"buttonIcon": "fa fa-plus",
"buttonLink": "org/teams/new",
"buttonTitle": " New team",
"proTip": "Assign folder and dashboard permissions to teams instead of users to ease administration.",
"proTipLink": "",
"proTipLinkTitle": "",
"proTipTarget": "_blank",
"title": "You haven't created any teams yet.",
}
}
/>
</div>
</div>
</div>
`;
`;
...
...
public/app/features/teams/state/reducers.ts
View file @
02e7d713
import
{
Team
,
TeamGroup
,
TeamMember
,
TeamsState
,
TeamState
}
from
'app/types'
;
import
{
Team
,
TeamGroup
,
TeamMember
,
TeamsState
,
TeamState
}
from
'app/types'
;
import
{
Action
,
ActionTypes
}
from
'./actions'
;
import
{
Action
,
ActionTypes
}
from
'./actions'
;
export
const
initialTeamsState
:
TeamsState
=
{
teams
:
[],
searchQuery
:
''
};
export
const
initialTeamsState
:
TeamsState
=
{
teams
:
[],
searchQuery
:
''
,
hasFetched
:
false
};
export
const
initialTeamState
:
TeamState
=
{
export
const
initialTeamState
:
TeamState
=
{
team
:
{}
as
Team
,
team
:
{}
as
Team
,
members
:
[]
as
TeamMember
[],
members
:
[]
as
TeamMember
[],
...
@@ -12,7 +12,7 @@ export const initialTeamState: TeamState = {
...
@@ -12,7 +12,7 @@ export const initialTeamState: TeamState = {
export
const
teamsReducer
=
(
state
=
initialTeamsState
,
action
:
Action
):
TeamsState
=>
{
export
const
teamsReducer
=
(
state
=
initialTeamsState
,
action
:
Action
):
TeamsState
=>
{
switch
(
action
.
type
)
{
switch
(
action
.
type
)
{
case
ActionTypes
.
LoadTeams
:
case
ActionTypes
.
LoadTeams
:
return
{
...
state
,
teams
:
action
.
payload
};
return
{
...
state
,
hasFetched
:
true
,
teams
:
action
.
payload
};
case
ActionTypes
.
SetSearchQuery
:
case
ActionTypes
.
SetSearchQuery
:
return
{
...
state
,
searchQuery
:
action
.
payload
};
return
{
...
state
,
searchQuery
:
action
.
payload
};
...
...
public/app/features/teams/state/selectors.test.ts
View file @
02e7d713
...
@@ -7,7 +7,7 @@ describe('Teams selectors', () => {
...
@@ -7,7 +7,7 @@ describe('Teams selectors', () => {
const
mockTeams
=
getMultipleMockTeams
(
5
);
const
mockTeams
=
getMultipleMockTeams
(
5
);
it
(
'should return teams if no search query'
,
()
=>
{
it
(
'should return teams if no search query'
,
()
=>
{
const
mockState
:
TeamsState
=
{
teams
:
mockTeams
,
searchQuery
:
''
};
const
mockState
:
TeamsState
=
{
teams
:
mockTeams
,
searchQuery
:
''
,
hasFetched
:
false
};
const
teams
=
getTeams
(
mockState
);
const
teams
=
getTeams
(
mockState
);
...
@@ -15,7 +15,7 @@ describe('Teams selectors', () => {
...
@@ -15,7 +15,7 @@ describe('Teams selectors', () => {
});
});
it
(
'Should filter teams if search query'
,
()
=>
{
it
(
'Should filter teams if search query'
,
()
=>
{
const
mockState
:
TeamsState
=
{
teams
:
mockTeams
,
searchQuery
:
'5'
};
const
mockState
:
TeamsState
=
{
teams
:
mockTeams
,
searchQuery
:
'5'
,
hasFetched
:
false
};
const
teams
=
getTeams
(
mockState
);
const
teams
=
getTeams
(
mockState
);
...
...
public/app/features/users/UsersListPage.test.tsx
View file @
02e7d713
...
@@ -22,6 +22,7 @@ const setup = (propOverrides?: object) => {
...
@@ -22,6 +22,7 @@ const setup = (propOverrides?: object) => {
updateUser
:
jest
.
fn
(),
updateUser
:
jest
.
fn
(),
removeUser
:
jest
.
fn
(),
removeUser
:
jest
.
fn
(),
setUsersSearchQuery
:
jest
.
fn
(),
setUsersSearchQuery
:
jest
.
fn
(),
hasFetched
:
false
,
};
};
Object
.
assign
(
props
,
propOverrides
);
Object
.
assign
(
props
,
propOverrides
);
...
@@ -41,6 +42,14 @@ describe('Render', () => {
...
@@ -41,6 +42,14 @@ describe('Render', () => {
expect
(
wrapper
).
toMatchSnapshot
();
expect
(
wrapper
).
toMatchSnapshot
();
});
});
it
(
'should render List page'
,
()
=>
{
const
{
wrapper
}
=
setup
({
hasFetched
:
true
,
});
expect
(
wrapper
).
toMatchSnapshot
();
});
});
});
describe
(
'Functions'
,
()
=>
{
describe
(
'Functions'
,
()
=>
{
...
...
public/app/features/users/UsersListPage.tsx
View file @
02e7d713
...
@@ -3,8 +3,9 @@ import { hot } from 'react-hot-loader';
...
@@ -3,8 +3,9 @@ import { hot } from 'react-hot-loader';
import
{
connect
}
from
'react-redux'
;
import
{
connect
}
from
'react-redux'
;
import
Remarkable
from
'remarkable'
;
import
Remarkable
from
'remarkable'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
PageLoader
from
'app/core/components/PageLoader/PageLoader'
;
import
UsersActionBar
from
'./UsersActionBar'
;
import
UsersActionBar
from
'./UsersActionBar'
;
import
UsersTable
from
'
app/features/users
/UsersTable'
;
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'
;
...
@@ -18,6 +19,7 @@ export interface Props {
...
@@ -18,6 +19,7 @@ export interface Props {
users
:
OrgUser
[];
users
:
OrgUser
[];
searchQuery
:
string
;
searchQuery
:
string
;
externalUserMngInfo
:
string
;
externalUserMngInfo
:
string
;
hasFetched
:
boolean
;
loadUsers
:
typeof
loadUsers
;
loadUsers
:
typeof
loadUsers
;
loadInvitees
:
typeof
loadInvitees
;
loadInvitees
:
typeof
loadInvitees
;
setUsersSearchQuery
:
typeof
setUsersSearchQuery
;
setUsersSearchQuery
:
typeof
setUsersSearchQuery
;
...
@@ -87,8 +89,24 @@ export class UsersListPage extends PureComponent<Props, State> {
...
@@ -87,8 +89,24 @@ export class UsersListPage extends PureComponent<Props, State> {
}));
}));
};
};
renderTable
()
{
const
{
invitees
,
users
}
=
this
.
props
;
if
(
this
.
state
.
showInvites
)
{
return
<
InviteesTable
invitees=
{
invitees
}
onRevokeInvite=
{
code
=>
this
.
onRevokeInvite
(
code
)
}
/>;
}
else
{
return
(
<
UsersTable
users=
{
users
}
onRoleChange=
{
(
role
,
user
)
=>
this
.
onRoleChange
(
role
,
user
)
}
onRemoveUser=
{
user
=>
this
.
onRemoveUser
(
user
)
}
/>
);
}
}
render
()
{
render
()
{
const
{
invitees
,
navModel
,
users
}
=
this
.
props
;
const
{
navModel
,
hasFetched
}
=
this
.
props
;
const
externalUserMngInfoHtml
=
this
.
externalUserMngInfoHtml
;
const
externalUserMngInfoHtml
=
this
.
externalUserMngInfoHtml
;
return
(
return
(
...
@@ -99,15 +117,7 @@ export class UsersListPage extends PureComponent<Props, State> {
...
@@ -99,15 +117,7 @@ export class UsersListPage extends PureComponent<Props, State> {
{
externalUserMngInfoHtml
&&
(
{
externalUserMngInfoHtml
&&
(
<
div
className=
"grafana-info-box"
dangerouslySetInnerHTML=
{
{
__html
:
externalUserMngInfoHtml
}
}
/>
<
div
className=
"grafana-info-box"
dangerouslySetInnerHTML=
{
{
__html
:
externalUserMngInfoHtml
}
}
/>
)
}
)
}
{
this
.
state
.
showInvites
?
(
{
hasFetched
?
this
.
renderTable
()
:
<
PageLoader
pageName=
"Users"
/>
}
<
InviteesTable
invitees=
{
invitees
}
onRevokeInvite=
{
code
=>
this
.
onRevokeInvite
(
code
)
}
/>
)
:
(
<
UsersTable
users=
{
users
}
onRoleChange=
{
(
role
,
user
)
=>
this
.
onRoleChange
(
role
,
user
)
}
onRemoveUser=
{
user
=>
this
.
onRemoveUser
(
user
)
}
/>
)
}
</
div
>
</
div
>
</
div
>
</
div
>
);
);
...
@@ -121,6 +131,7 @@ function mapStateToProps(state) {
...
@@ -121,6 +131,7 @@ function mapStateToProps(state) {
searchQuery
:
getUsersSearchQuery
(
state
.
users
),
searchQuery
:
getUsersSearchQuery
(
state
.
users
),
invitees
:
getInvitees
(
state
.
users
),
invitees
:
getInvitees
(
state
.
users
),
externalUserMngInfo
:
state
.
users
.
externalUserMngInfo
,
externalUserMngInfo
:
state
.
users
.
externalUserMngInfo
,
hasFetched
:
state
.
users
.
hasFetched
,
};
};
}
}
...
...
public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap
View file @
02e7d713
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render
component
1`] = `
exports[`Render should render
List page
1`] = `
<div>
<div>
<PageHeader
<PageHeader
model={Object {}}
model={Object {}}
...
@@ -20,3 +20,22 @@ exports[`Render should render component 1`] = `
...
@@ -20,3 +20,22 @@ exports[`Render should render component 1`] = `
</div>
</div>
</div>
</div>
`;
`;
exports[`Render should render component 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<Connect(UsersActionBar)
onShowInvites={[Function]}
showInvites={false}
/>
<PageLoader
pageName="Users"
/>
</div>
</div>
`;
public/app/features/users/state/reducers.ts
View file @
02e7d713
import
{
Invitee
,
OrgUser
,
UsersState
}
from
'app/types'
;
import
{
Invitee
,
OrgUser
,
UsersState
}
from
'app/types'
;
import
{
Action
,
ActionTypes
}
from
'./actions'
;
import
{
Action
,
ActionTypes
}
from
'./actions'
;
import
config
from
'
../../..
/core/config'
;
import
config
from
'
app
/core/config'
;
export
const
initialState
:
UsersState
=
{
export
const
initialState
:
UsersState
=
{
invitees
:
[]
as
Invitee
[],
invitees
:
[]
as
Invitee
[],
...
@@ -10,15 +10,16 @@ export const initialState: UsersState = {
...
@@ -10,15 +10,16 @@ export const initialState: UsersState = {
externalUserMngInfo
:
config
.
externalUserMngInfo
,
externalUserMngInfo
:
config
.
externalUserMngInfo
,
externalUserMngLinkName
:
config
.
externalUserMngLinkName
,
externalUserMngLinkName
:
config
.
externalUserMngLinkName
,
externalUserMngLinkUrl
:
config
.
externalUserMngLinkUrl
,
externalUserMngLinkUrl
:
config
.
externalUserMngLinkUrl
,
hasFetched
:
false
,
};
};
export
const
usersReducer
=
(
state
=
initialState
,
action
:
Action
):
UsersState
=>
{
export
const
usersReducer
=
(
state
=
initialState
,
action
:
Action
):
UsersState
=>
{
switch
(
action
.
type
)
{
switch
(
action
.
type
)
{
case
ActionTypes
.
LoadUsers
:
case
ActionTypes
.
LoadUsers
:
return
{
...
state
,
users
:
action
.
payload
};
return
{
...
state
,
hasFetched
:
true
,
users
:
action
.
payload
};
case
ActionTypes
.
LoadInvitees
:
case
ActionTypes
.
LoadInvitees
:
return
{
...
state
,
invitees
:
action
.
payload
};
return
{
...
state
,
hasFetched
:
true
,
invitees
:
action
.
payload
};
case
ActionTypes
.
SetUsersSearchQuery
:
case
ActionTypes
.
SetUsersSearchQuery
:
return
{
...
state
,
searchQuery
:
action
.
payload
};
return
{
...
state
,
searchQuery
:
action
.
payload
};
...
...
public/app/types/apiKeys.ts
View file @
02e7d713
...
@@ -14,4 +14,5 @@ export interface NewApiKey {
...
@@ -14,4 +14,5 @@ export interface NewApiKey {
export
interface
ApiKeysState
{
export
interface
ApiKeysState
{
keys
:
ApiKey
[];
keys
:
ApiKey
[];
searchQuery
:
string
;
searchQuery
:
string
;
hasFetched
:
boolean
;
}
}
public/app/types/datasources.ts
View file @
02e7d713
...
@@ -25,4 +25,5 @@ export interface DataSourcesState {
...
@@ -25,4 +25,5 @@ export interface DataSourcesState {
layoutMode
:
LayoutMode
;
layoutMode
:
LayoutMode
;
dataSourcesCount
:
number
;
dataSourcesCount
:
number
;
dataSourceTypes
:
Plugin
[];
dataSourceTypes
:
Plugin
[];
hasFetched
:
boolean
;
}
}
public/app/types/plugins.ts
View file @
02e7d713
...
@@ -44,4 +44,5 @@ export interface PluginsState {
...
@@ -44,4 +44,5 @@ export interface PluginsState {
plugins
:
Plugin
[];
plugins
:
Plugin
[];
searchQuery
:
string
;
searchQuery
:
string
;
layoutMode
:
string
;
layoutMode
:
string
;
hasFetched
:
boolean
;
}
}
public/app/types/teams.ts
View file @
02e7d713
...
@@ -23,6 +23,7 @@ export interface TeamGroup {
...
@@ -23,6 +23,7 @@ export interface TeamGroup {
export
interface
TeamsState
{
export
interface
TeamsState
{
teams
:
Team
[];
teams
:
Team
[];
searchQuery
:
string
;
searchQuery
:
string
;
hasFetched
:
boolean
;
}
}
export
interface
TeamState
{
export
interface
TeamState
{
...
...
public/app/types/user.ts
View file @
02e7d713
...
@@ -41,4 +41,5 @@ export interface UsersState {
...
@@ -41,4 +41,5 @@ export interface UsersState {
externalUserMngLinkUrl
:
string
;
externalUserMngLinkUrl
:
string
;
externalUserMngLinkName
:
string
;
externalUserMngLinkName
:
string
;
externalUserMngInfo
:
string
;
externalUserMngInfo
:
string
;
hasFetched
:
boolean
;
}
}
public/app/types/users.ts
deleted
100644 → 0
View file @
974eddee
export
interface
Invitee
{
code
:
string
;
createdOn
:
string
;
email
:
string
;
emailSent
:
boolean
;
emailSentOn
:
string
;
id
:
number
;
invitedByEmail
:
string
;
invitedByLogin
:
string
;
invitedByName
:
string
;
name
:
string
;
orgId
:
number
;
role
:
string
;
status
:
string
;
url
:
string
;
}
export
interface
User
{
avatarUrl
:
string
;
email
:
string
;
lastSeenAt
:
string
;
lastSeenAtAge
:
string
;
login
:
string
;
orgId
:
number
;
role
:
string
;
userId
:
number
;
}
export
interface
UsersState
{
users
:
User
[];
invitees
:
Invitee
[];
searchQuery
:
string
;
canInvite
:
boolean
;
externalUserMngLinkUrl
:
string
;
externalUserMngLinkName
:
string
;
externalUserMngInfo
:
string
;
}
public/sass/_grafana.scss
View file @
02e7d713
...
@@ -95,7 +95,8 @@
...
@@ -95,7 +95,8 @@
@import
'components/user-picker'
;
@import
'components/user-picker'
;
@import
'components/description-picker'
;
@import
'components/description-picker'
;
@import
'components/delete_button'
;
@import
'components/delete_button'
;
@import
'components/_add_data_source.scss'
;
@import
'components/add_data_source.scss'
;
@import
'components/page_loader'
;
// PAGES
// PAGES
@import
'pages/login'
;
@import
'pages/login'
;
...
...
public/sass/components/_page_loader.scss
0 → 100644
View file @
02e7d713
.page-loader-wrapper
{
padding-top
:
100px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
flex-direction
:
column
;
&
__spinner
{
font-size
:
32px
;
margin-bottom
:
$panel-margin
;
}
&
__text
{
font-size
:
14px
;
}
}
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