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
f37a60dc
Commit
f37a60dc
authored
Oct 02, 2018
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'data-sources-list-to-react'
parents
8e9c0a44
8fd1d8a0
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
831 additions
and
129 deletions
+831
-129
public/app/features/datasources/DataSourceList.test.tsx
+22
-0
public/app/features/datasources/DataSourcesActionBar.test.tsx
+23
-0
public/app/features/datasources/DataSourcesActionBar.tsx
+62
-0
public/app/features/datasources/DataSourcesList.tsx
+34
-0
public/app/features/datasources/DataSourcesListItem.test.tsx
+20
-0
public/app/features/datasources/DataSourcesListItem.tsx
+35
-0
public/app/features/datasources/DataSourcesListPage.test.tsx
+37
-0
public/app/features/datasources/DataSourcesListPage.tsx
+76
-0
public/app/features/datasources/__mocks__/dataSourcesMocks.ts
+45
-0
public/app/features/datasources/__snapshots__/DataSourceList.test.tsx.snap
+108
-0
public/app/features/datasources/__snapshots__/DataSourcesActionBar.test.tsx.snap
+42
-0
public/app/features/datasources/__snapshots__/DataSourcesListItem.test.tsx.snap
+45
-0
public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap
+164
-0
public/app/features/datasources/state/actions.ts
+51
-0
public/app/features/datasources/state/reducers.ts
+29
-0
public/app/features/datasources/state/selectors.ts
+11
-0
public/app/features/plugins/all.ts
+0
-1
public/app/features/plugins/ds_list_ctrl.ts
+0
-61
public/app/features/plugins/partials/ds_list.html
+0
-63
public/app/routes/routes.ts
+5
-3
public/app/store/configureStore.ts
+2
-0
public/app/types/datasources.ts
+18
-0
public/app/types/index.ts
+2
-1
No files found.
public/app/features/datasources/DataSourceList.test.tsx
0 → 100644
View file @
f37a60dc
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
DataSourcesList
from
'./DataSourcesList'
;
import
{
getMockDataSources
}
from
'./__mocks__/dataSourcesMocks'
;
import
{
LayoutModes
}
from
'../../core/components/LayoutSelector/LayoutSelector'
;
const
setup
=
()
=>
{
const
props
=
{
dataSources
:
getMockDataSources
(
3
),
layoutMode
:
LayoutModes
.
Grid
,
};
return
shallow
(<
DataSourcesList
{
...
props
}
/>);
};
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
wrapper
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
});
public/app/features/datasources/DataSourcesActionBar.test.tsx
0 → 100644
View file @
f37a60dc
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
{
DataSourcesActionBar
,
Props
}
from
'./DataSourcesActionBar'
;
import
{
LayoutModes
}
from
'../../core/components/LayoutSelector/LayoutSelector'
;
const
setup
=
(
propOverrides
?:
object
)
=>
{
const
props
:
Props
=
{
layoutMode
:
LayoutModes
.
Grid
,
searchQuery
:
''
,
setDataSourcesLayoutMode
:
jest
.
fn
(),
setDataSourcesSearchQuery
:
jest
.
fn
(),
};
return
shallow
(<
DataSourcesActionBar
{
...
props
}
/>);
};
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
wrapper
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
});
public/app/features/datasources/DataSourcesActionBar.tsx
0 → 100644
View file @
f37a60dc
import
React
,
{
PureComponent
}
from
'react'
;
import
{
connect
}
from
'react-redux'
;
import
LayoutSelector
,
{
LayoutMode
}
from
'../../core/components/LayoutSelector/LayoutSelector'
;
import
{
setDataSourcesLayoutMode
,
setDataSourcesSearchQuery
}
from
'./state/actions'
;
import
{
getDataSourcesLayoutMode
,
getDataSourcesSearchQuery
}
from
'./state/selectors'
;
export
interface
Props
{
searchQuery
:
string
;
layoutMode
:
LayoutMode
;
setDataSourcesLayoutMode
:
typeof
setDataSourcesLayoutMode
;
setDataSourcesSearchQuery
:
typeof
setDataSourcesSearchQuery
;
}
export
class
DataSourcesActionBar
extends
PureComponent
<
Props
>
{
onSearchQueryChange
=
event
=>
{
this
.
props
.
setDataSourcesSearchQuery
(
event
.
target
.
value
);
};
render
()
{
const
{
searchQuery
,
layoutMode
,
setDataSourcesLayoutMode
}
=
this
.
props
;
return
(
<
div
className=
"page-action-bar"
>
<
div
className=
"gf-form gf-form--grow"
>
<
label
className=
"gf-form--has-input-icon"
>
<
input
type=
"text"
className=
"gf-form-input width-20"
value=
{
searchQuery
}
onChange=
{
this
.
onSearchQueryChange
}
placeholder=
"Filter by name or type"
/>
<
i
className=
"gf-form-input-icon fa fa-search"
/>
</
label
>
<
LayoutSelector
mode=
{
layoutMode
}
onLayoutModeChanged=
{
(
mode
:
LayoutMode
)
=>
setDataSourcesLayoutMode
(
mode
)
}
/>
</
div
>
<
div
className=
"page-action-bar__spacer"
/>
<
a
className=
"page-header__cta btn btn-success"
href=
"datasources/new"
>
<
i
className=
"fa fa-plus"
/>
Add data source
</
a
>
</
div
>
);
}
}
function
mapStateToProps
(
state
)
{
return
{
searchQuery
:
getDataSourcesSearchQuery
(
state
.
dataSources
),
layoutMode
:
getDataSourcesLayoutMode
(
state
.
dataSources
),
};
}
const
mapDispatchToProps
=
{
setDataSourcesLayoutMode
,
setDataSourcesSearchQuery
,
};
export
default
connect
(
mapStateToProps
,
mapDispatchToProps
)(
DataSourcesActionBar
);
public/app/features/datasources/DataSourcesList.tsx
0 → 100644
View file @
f37a60dc
import
React
,
{
PureComponent
}
from
'react'
;
import
classNames
from
'classnames/bind'
;
import
DataSourcesListItem
from
'./DataSourcesListItem'
;
import
{
DataSource
}
from
'app/types'
;
import
{
LayoutMode
,
LayoutModes
}
from
'../../core/components/LayoutSelector/LayoutSelector'
;
export
interface
Props
{
dataSources
:
DataSource
[];
layoutMode
:
LayoutMode
;
}
export
class
DataSourcesList
extends
PureComponent
<
Props
>
{
render
()
{
const
{
dataSources
,
layoutMode
}
=
this
.
props
;
const
listStyle
=
classNames
({
'card-section'
:
true
,
'card-list-layout-grid'
:
layoutMode
===
LayoutModes
.
Grid
,
'card-list-layout-list'
:
layoutMode
===
LayoutModes
.
List
,
});
return
(
<
section
className=
{
listStyle
}
>
<
ol
className=
"card-list"
>
{
dataSources
.
map
((
dataSource
,
index
)
=>
{
return
<
DataSourcesListItem
dataSource=
{
dataSource
}
key=
{
`${dataSource.id}-${index}`
}
/>;
})
}
</
ol
>
</
section
>
);
}
}
export
default
DataSourcesList
;
public/app/features/datasources/DataSourcesListItem.test.tsx
0 → 100644
View file @
f37a60dc
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
DataSourcesListItem
from
'./DataSourcesListItem'
;
import
{
getMockDataSource
}
from
'./__mocks__/dataSourcesMocks'
;
const
setup
=
()
=>
{
const
props
=
{
dataSource
:
getMockDataSource
(),
};
return
shallow
(<
DataSourcesListItem
{
...
props
}
/>);
};
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
wrapper
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
});
public/app/features/datasources/DataSourcesListItem.tsx
0 → 100644
View file @
f37a60dc
import
React
,
{
PureComponent
}
from
'react'
;
import
{
DataSource
}
from
'app/types'
;
export
interface
Props
{
dataSource
:
DataSource
;
}
export
class
DataSourcesListItem
extends
PureComponent
<
Props
>
{
render
()
{
const
{
dataSource
}
=
this
.
props
;
return
(
<
li
className=
"card-item-wrapper"
>
<
a
className=
"card-item"
href=
{
`datasources/edit/${dataSource.id}`
}
>
<
div
className=
"card-item-header"
>
<
div
className=
"card-item-type"
>
{
dataSource
.
type
}
</
div
>
</
div
>
<
div
className=
"card-item-body"
>
<
figure
className=
"card-item-figure"
>
<
img
src=
{
dataSource
.
typeLogoUrl
}
/>
</
figure
>
<
div
className=
"card-item-details"
>
<
div
className=
"card-item-name"
>
{
dataSource
.
name
}
{
dataSource
.
isDefault
&&
<
span
className=
"btn btn-secondary btn-mini"
>
default
</
span
>
}
</
div
>
<
div
className=
"card-item-sub-name"
>
{
dataSource
.
url
}
</
div
>
</
div
>
</
div
>
</
a
>
</
li
>
);
}
}
export
default
DataSourcesListItem
;
public/app/features/datasources/DataSourcesListPage.test.tsx
0 → 100644
View file @
f37a60dc
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
{
DataSourcesListPage
,
Props
}
from
'./DataSourcesListPage'
;
import
{
DataSource
,
NavModel
}
from
'app/types'
;
import
{
LayoutModes
}
from
'../../core/components/LayoutSelector/LayoutSelector'
;
import
{
getMockDataSources
}
from
'./__mocks__/dataSourcesMocks'
;
const
setup
=
(
propOverrides
?:
object
)
=>
{
const
props
:
Props
=
{
dataSources
:
[]
as
DataSource
[],
layoutMode
:
LayoutModes
.
Grid
,
loadDataSources
:
jest
.
fn
(),
navModel
:
{}
as
NavModel
,
dataSourcesCount
:
0
,
};
Object
.
assign
(
props
,
propOverrides
);
return
shallow
(<
DataSourcesListPage
{
...
props
}
/>);
};
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
wrapper
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render action bar and datasources'
,
()
=>
{
const
wrapper
=
setup
({
dataSources
:
getMockDataSources
(
5
),
dataSourcesCount
:
5
,
});
expect
(
wrapper
).
toMatchSnapshot
();
});
});
public/app/features/datasources/DataSourcesListPage.tsx
0 → 100644
View file @
f37a60dc
import
React
,
{
PureComponent
}
from
'react'
;
import
{
connect
}
from
'react-redux'
;
import
{
hot
}
from
'react-hot-loader'
;
import
PageHeader
from
'../../core/components/PageHeader/PageHeader'
;
import
DataSourcesActionBar
from
'./DataSourcesActionBar'
;
import
DataSourcesList
from
'./DataSourcesList'
;
import
{
loadDataSources
}
from
'./state/actions'
;
import
{
getDataSources
,
getDataSourcesCount
,
getDataSourcesLayoutMode
}
from
'./state/selectors'
;
import
{
getNavModel
}
from
'../../core/selectors/navModel'
;
import
{
DataSource
,
NavModel
}
from
'app/types'
;
import
{
LayoutMode
}
from
'../../core/components/LayoutSelector/LayoutSelector'
;
import
EmptyListCTA
from
'../../core/components/EmptyListCTA/EmptyListCTA'
;
export
interface
Props
{
navModel
:
NavModel
;
dataSources
:
DataSource
[];
dataSourcesCount
:
number
;
layoutMode
:
LayoutMode
;
loadDataSources
:
typeof
loadDataSources
;
}
const
emptyListModel
=
{
title
:
'There are no data sources defined yet'
,
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'
,
};
export
class
DataSourcesListPage
extends
PureComponent
<
Props
>
{
componentDidMount
()
{
this
.
fetchDataSources
();
}
async
fetchDataSources
()
{
return
await
this
.
props
.
loadDataSources
();
}
render
()
{
const
{
dataSources
,
dataSourcesCount
,
navModel
,
layoutMode
}
=
this
.
props
;
return
(
<
div
>
<
PageHeader
model=
{
navModel
}
/>
<
div
className=
"page-container page-body"
>
{
dataSourcesCount
===
0
?
(
<
EmptyListCTA
model=
{
emptyListModel
}
/>
)
:
(
[
<
DataSourcesActionBar
key=
"action-bar"
/>,
<
DataSourcesList
dataSources=
{
dataSources
}
layoutMode=
{
layoutMode
}
key=
"list"
/>,
]
)
}
</
div
>
</
div
>
);
}
}
function
mapStateToProps
(
state
)
{
return
{
navModel
:
getNavModel
(
state
.
navIndex
,
'datasources'
),
dataSources
:
getDataSources
(
state
.
dataSources
),
layoutMode
:
getDataSourcesLayoutMode
(
state
.
dataSources
),
dataSourcesCount
:
getDataSourcesCount
(
state
.
dataSources
),
};
}
const
mapDispatchToProps
=
{
loadDataSources
,
};
export
default
hot
(
module
)(
connect
(
mapStateToProps
,
mapDispatchToProps
)(
DataSourcesListPage
));
public/app/features/datasources/__mocks__/dataSourcesMocks.ts
0 → 100644
View file @
f37a60dc
import
{
DataSource
}
from
'app/types'
;
export
const
getMockDataSources
=
(
amount
:
number
):
DataSource
[]
=>
{
const
dataSources
=
[];
for
(
let
i
=
0
;
i
<=
amount
;
i
++
)
{
dataSources
.
push
({
access
:
''
,
basicAuth
:
false
,
database
:
`database-
${
i
}
`
,
id
:
i
,
isDefault
:
false
,
jsonData
:
{
authType
:
'credentials'
,
defaultRegion
:
'eu-west-2'
},
name
:
`dataSource-
${
i
}
`
,
orgId
:
1
,
password
:
''
,
readOnly
:
false
,
type
:
'cloudwatch'
,
typeLogoUrl
:
'public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png'
,
url
:
''
,
user
:
''
,
});
}
return
dataSources
;
};
export
const
getMockDataSource
=
():
DataSource
=>
{
return
{
access
:
''
,
basicAuth
:
false
,
database
:
''
,
id
:
13
,
isDefault
:
false
,
jsonData
:
{
authType
:
'credentials'
,
defaultRegion
:
'eu-west-2'
},
name
:
'gdev-cloudwatch'
,
orgId
:
1
,
password
:
''
,
readOnly
:
false
,
type
:
'cloudwatch'
,
typeLogoUrl
:
'public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png'
,
url
:
''
,
user
:
''
,
};
};
public/app/features/datasources/__snapshots__/DataSourceList.test.tsx.snap
0 → 100644
View file @
f37a60dc
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<section
className="card-section card-list-layout-grid"
>
<ol
className="card-list"
>
<DataSourcesListItem
dataSource={
Object {
"access": "",
"basicAuth": false,
"database": "database-0",
"id": 0,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-0",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
}
}
key="0-0"
/>
<DataSourcesListItem
dataSource={
Object {
"access": "",
"basicAuth": false,
"database": "database-1",
"id": 1,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-1",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
}
}
key="1-1"
/>
<DataSourcesListItem
dataSource={
Object {
"access": "",
"basicAuth": false,
"database": "database-2",
"id": 2,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-2",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
}
}
key="2-2"
/>
<DataSourcesListItem
dataSource={
Object {
"access": "",
"basicAuth": false,
"database": "database-3",
"id": 3,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-3",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
}
}
key="3-3"
/>
</ol>
</section>
`;
public/app/features/datasources/__snapshots__/DataSourcesActionBar.test.tsx.snap
0 → 100644
View file @
f37a60dc
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<div
className="page-action-bar"
>
<div
className="gf-form gf-form--grow"
>
<label
className="gf-form--has-input-icon"
>
<input
className="gf-form-input width-20"
onChange={[Function]}
placeholder="Filter by name or type"
type="text"
value=""
/>
<i
className="gf-form-input-icon fa fa-search"
/>
</label>
<LayoutSelector
mode="grid"
onLayoutModeChanged={[Function]}
/>
</div>
<div
className="page-action-bar__spacer"
/>
<a
className="page-header__cta btn btn-success"
href="datasources/new"
>
<i
className="fa fa-plus"
/>
Add data source
</a>
</div>
`;
public/app/features/datasources/__snapshots__/DataSourcesListItem.test.tsx.snap
0 → 100644
View file @
f37a60dc
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<li
className="card-item-wrapper"
>
<a
className="card-item"
href="datasources/edit/13"
>
<div
className="card-item-header"
>
<div
className="card-item-type"
>
cloudwatch
</div>
</div>
<div
className="card-item-body"
>
<figure
className="card-item-figure"
>
<img
src="public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png"
/>
</figure>
<div
className="card-item-details"
>
<div
className="card-item-name"
>
gdev-cloudwatch
</div>
<div
className="card-item-sub-name"
/>
</div>
</div>
</a>
</li>
`;
public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap
0 → 100644
View file @
f37a60dc
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render action bar and datasources 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<Connect(DataSourcesActionBar)
key="action-bar"
/>
<DataSourcesList
dataSources={
Array [
Object {
"access": "",
"basicAuth": false,
"database": "database-0",
"id": 0,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-0",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
},
Object {
"access": "",
"basicAuth": false,
"database": "database-1",
"id": 1,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-1",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
},
Object {
"access": "",
"basicAuth": false,
"database": "database-2",
"id": 2,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-2",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
},
Object {
"access": "",
"basicAuth": false,
"database": "database-3",
"id": 3,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-3",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
},
Object {
"access": "",
"basicAuth": false,
"database": "database-4",
"id": 4,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-4",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
},
Object {
"access": "",
"basicAuth": false,
"database": "database-5",
"id": 5,
"isDefault": false,
"jsonData": Object {
"authType": "credentials",
"defaultRegion": "eu-west-2",
},
"name": "dataSource-5",
"orgId": 1,
"password": "",
"readOnly": false,
"type": "cloudwatch",
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
"url": "",
"user": "",
},
]
}
key="list"
layoutMode="grid"
/>
</div>
</div>
`;
exports[`Render should render component 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<EmptyListCTA
model={
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>
`;
public/app/features/datasources/state/actions.ts
0 → 100644
View file @
f37a60dc
import
{
ThunkAction
}
from
'redux-thunk'
;
import
{
DataSource
,
StoreState
}
from
'app/types'
;
import
{
getBackendSrv
}
from
'../../../core/services/backend_srv'
;
import
{
LayoutMode
}
from
'../../../core/components/LayoutSelector/LayoutSelector'
;
export
enum
ActionTypes
{
LoadDataSources
=
'LOAD_DATA_SOURCES'
,
SetDataSourcesSearchQuery
=
'SET_DATA_SOURCES_SEARCH_QUERY'
,
SetDataSourcesLayoutMode
=
'SET_DATA_SOURCES_LAYOUT_MODE'
,
}
export
interface
LoadDataSourcesAction
{
type
:
ActionTypes
.
LoadDataSources
;
payload
:
DataSource
[];
}
export
interface
SetDataSourcesSearchQueryAction
{
type
:
ActionTypes
.
SetDataSourcesSearchQuery
;
payload
:
string
;
}
export
interface
SetDataSourcesLayoutModeAction
{
type
:
ActionTypes
.
SetDataSourcesLayoutMode
;
payload
:
LayoutMode
;
}
const
dataSourcesLoaded
=
(
dataSources
:
DataSource
[]):
LoadDataSourcesAction
=>
({
type
:
ActionTypes
.
LoadDataSources
,
payload
:
dataSources
,
});
export
const
setDataSourcesSearchQuery
=
(
searchQuery
:
string
):
SetDataSourcesSearchQueryAction
=>
({
type
:
ActionTypes
.
SetDataSourcesSearchQuery
,
payload
:
searchQuery
,
});
export
const
setDataSourcesLayoutMode
=
(
layoutMode
:
LayoutMode
):
SetDataSourcesLayoutModeAction
=>
({
type
:
ActionTypes
.
SetDataSourcesLayoutMode
,
payload
:
layoutMode
,
});
export
type
Action
=
LoadDataSourcesAction
|
SetDataSourcesSearchQueryAction
|
SetDataSourcesLayoutModeAction
;
type
ThunkResult
<
R
>
=
ThunkAction
<
R
,
StoreState
,
undefined
,
Action
>
;
export
function
loadDataSources
():
ThunkResult
<
void
>
{
return
async
dispatch
=>
{
const
response
=
await
getBackendSrv
().
get
(
'/api/datasources'
);
dispatch
(
dataSourcesLoaded
(
response
));
};
}
public/app/features/datasources/state/reducers.ts
0 → 100644
View file @
f37a60dc
import
{
DataSource
,
DataSourcesState
}
from
'app/types'
;
import
{
Action
,
ActionTypes
}
from
'./actions'
;
import
{
LayoutModes
}
from
'../../../core/components/LayoutSelector/LayoutSelector'
;
const
initialState
:
DataSourcesState
=
{
dataSources
:
[]
as
DataSource
[],
layoutMode
:
LayoutModes
.
Grid
,
searchQuery
:
''
,
dataSourcesCount
:
0
,
};
export
const
dataSourcesReducer
=
(
state
=
initialState
,
action
:
Action
):
DataSourcesState
=>
{
switch
(
action
.
type
)
{
case
ActionTypes
.
LoadDataSources
:
return
{
...
state
,
dataSources
:
action
.
payload
,
dataSourcesCount
:
action
.
payload
.
length
};
case
ActionTypes
.
SetDataSourcesSearchQuery
:
return
{
...
state
,
searchQuery
:
action
.
payload
};
case
ActionTypes
.
SetDataSourcesLayoutMode
:
return
{
...
state
,
layoutMode
:
action
.
payload
};
}
return
state
;
};
export
default
{
dataSources
:
dataSourcesReducer
,
};
public/app/features/datasources/state/selectors.ts
0 → 100644
View file @
f37a60dc
export
const
getDataSources
=
state
=>
{
const
regex
=
new
RegExp
(
state
.
searchQuery
,
'i'
);
return
state
.
dataSources
.
filter
(
dataSource
=>
{
return
regex
.
test
(
dataSource
.
name
)
||
regex
.
test
(
dataSource
.
database
);
});
};
export
const
getDataSourcesSearchQuery
=
state
=>
state
.
searchQuery
;
export
const
getDataSourcesLayoutMode
=
state
=>
state
.
layoutMode
;
export
const
getDataSourcesCount
=
state
=>
state
.
dataSourcesCount
;
public/app/features/plugins/all.ts
View file @
f37a60dc
...
...
@@ -3,6 +3,5 @@ import './plugin_page_ctrl';
import
'./import_list/import_list'
;
import
'./ds_edit_ctrl'
;
import
'./ds_dashboards_ctrl'
;
import
'./ds_list_ctrl'
;
import
'./datasource_srv'
;
import
'./plugin_component'
;
public/app/features/plugins/ds_list_ctrl.ts
deleted
100644 → 0
View file @
8e9c0a44
import
coreModule
from
'../../core/core_module'
;
import
_
from
'lodash'
;
export
class
DataSourcesCtrl
{
datasources
:
any
;
unfiltered
:
any
;
navModel
:
any
;
searchQuery
:
string
;
/** @ngInject */
constructor
(
private
$scope
,
private
backendSrv
,
private
datasourceSrv
,
private
navModelSrv
)
{
this
.
navModel
=
this
.
navModelSrv
.
getNav
(
'cfg'
,
'datasources'
,
0
);
backendSrv
.
get
(
'/api/datasources'
).
then
(
result
=>
{
this
.
datasources
=
result
;
this
.
unfiltered
=
result
;
});
}
onQueryUpdated
()
{
const
regex
=
new
RegExp
(
this
.
searchQuery
,
'ig'
);
this
.
datasources
=
_
.
filter
(
this
.
unfiltered
,
item
=>
{
regex
.
lastIndex
=
0
;
return
regex
.
test
(
item
.
name
)
||
regex
.
test
(
item
.
type
);
});
}
removeDataSourceConfirmed
(
ds
)
{
this
.
backendSrv
.
delete
(
'/api/datasources/'
+
ds
.
id
)
.
then
(
()
=>
{
this
.
$scope
.
appEvent
(
'alert-success'
,
[
'Datasource deleted'
,
''
]);
},
()
=>
{
this
.
$scope
.
appEvent
(
'alert-error'
,
[
'Unable to delete datasource'
,
''
]);
}
)
.
then
(()
=>
{
this
.
backendSrv
.
get
(
'/api/datasources'
).
then
(
result
=>
{
this
.
datasources
=
result
;
});
this
.
backendSrv
.
get
(
'/api/frontend/settings'
).
then
(
settings
=>
{
this
.
datasourceSrv
.
init
(
settings
.
datasources
);
});
});
}
removeDataSource
(
ds
)
{
this
.
$scope
.
appEvent
(
'confirm-modal'
,
{
title
:
'Delete'
,
text
:
'Are you sure you want to delete datasource '
+
ds
.
name
+
'?'
,
yesText
:
'Delete'
,
icon
:
'fa-trash'
,
onConfirm
:
()
=>
{
this
.
removeDataSourceConfirmed
(
ds
);
},
});
}
}
coreModule
.
controller
(
'DataSourcesCtrl'
,
DataSourcesCtrl
);
public/app/features/plugins/partials/ds_list.html
deleted
100644 → 0
View file @
8e9c0a44
<page-header
model=
"ctrl.navModel"
></page-header>
<div
class=
"page-container page-body"
>
<div
ng-if=
"ctrl.unfiltered.length"
>
<div
class=
"page-action-bar"
>
<div
class=
"gf-form gf-form--grow"
>
<label
class=
"gf-form--has-input-icon"
>
<input
type=
"text"
class=
"gf-form-input width-20"
ng-model=
"ctrl.searchQuery"
ng-change=
"ctrl.onQueryUpdated()"
placeholder=
"Filter by name or type"
/>
<i
class=
"gf-form-input-icon fa fa-search"
></i>
</label>
<layout-selector
/>
</div>
<div
class=
"page-action-bar__spacer"
></div>
<a
class=
"page-header__cta btn btn-success"
href=
"datasources/new"
>
<i
class=
"fa fa-plus"
></i>
Add data source
</a>
</div>
<section
class=
"card-section"
layout-mode
>
<ol
class=
"card-list"
>
<li
class=
"card-item-wrapper"
ng-repeat=
"ds in ctrl.datasources"
>
<a
class=
"card-item"
href=
"datasources/edit/{{ds.id}}/"
>
<div
class=
"card-item-header"
>
<div
class=
"card-item-type"
>
{{ds.type}}
</div>
</div>
<div
class=
"card-item-body"
>
<figure
class=
"card-item-figure"
>
<img
ng-src=
"{{ds.typeLogoUrl}}"
>
</figure>
<div
class=
"card-item-details"
>
<div
class=
"card-item-name"
>
{{ds.name}}
<span
ng-if=
"ds.isDefault"
>
<span
class=
"btn btn-secondary btn-mini"
>
default
</span>
</span>
</div>
<div
class=
"card-item-sub-name"
>
{{ds.url}}
</div>
</div>
</div>
</a>
</li>
</ol>
</section>
</div>
<div
ng-if=
"ctrl.unfiltered.length === 0"
>
<empty-list-cta
model=
"{
title: 'There are no data sources defined yet',
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'
}"
/>
</div>
</div>
public/app/routes/routes.ts
View file @
f37a60dc
...
...
@@ -9,6 +9,7 @@ import ApiKeys from 'app/features/api-keys/ApiKeysPage';
import
PluginListPage
from
'app/features/plugins/PluginListPage'
;
import
FolderSettingsPage
from
'app/features/folders/FolderSettingsPage'
;
import
FolderPermissions
from
'app/features/folders/FolderPermissions'
;
import
DataSourcesListPage
from
'app/features/datasources/DataSourcesListPage'
;
/** @ngInject */
export
function
setupAngularRoutes
(
$routeProvider
,
$locationProvider
)
{
...
...
@@ -63,9 +64,10 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
controllerAs
:
'ctrl'
,
})
.
when
(
'/datasources'
,
{
templateUrl
:
'public/app/features/plugins/partials/ds_list.html'
,
controller
:
'DataSourcesCtrl'
,
controllerAs
:
'ctrl'
,
template
:
'<react-container />'
,
resolve
:
{
component
:
()
=>
DataSourcesListPage
,
},
})
.
when
(
'/datasources/edit/:id'
,
{
templateUrl
:
'public/app/features/plugins/partials/ds_edit.html'
,
...
...
public/app/store/configureStore.ts
View file @
f37a60dc
...
...
@@ -8,6 +8,7 @@ import apiKeysReducers from 'app/features/api-keys/state/reducers';
import
foldersReducers
from
'app/features/folders/state/reducers'
;
import
dashboardReducers
from
'app/features/dashboard/state/reducers'
;
import
pluginReducers
from
'app/features/plugins/state/reducers'
;
import
dataSourcesReducers
from
'app/features/datasources/state/reducers'
;
const
rootReducer
=
combineReducers
({
...
sharedReducers
,
...
...
@@ -17,6 +18,7 @@ const rootReducer = combineReducers({
...
foldersReducers
,
...
dashboardReducers
,
...
pluginReducers
,
...
dataSourcesReducers
,
});
export
let
store
;
...
...
public/app/types/datasources.ts
View file @
f37a60dc
import
{
LayoutMode
}
from
'../core/components/LayoutSelector/LayoutSelector'
;
export
interface
DataSource
{
id
:
number
;
orgId
:
number
;
name
:
string
;
typeLogoUrl
:
string
;
type
:
string
;
access
:
string
;
url
:
string
;
password
:
string
;
user
:
string
;
database
:
string
;
basicAuth
:
false
;
isDefault
:
false
;
jsonData
:
{
authType
:
string
;
defaultRegion
:
string
};
readOnly
:
false
;
}
export
interface
DataSourcesState
{
dataSources
:
DataSource
[];
searchQuery
:
string
;
layoutMode
:
LayoutMode
;
dataSourcesCount
:
number
;
}
public/app/types/index.ts
View file @
f37a60dc
...
...
@@ -5,9 +5,9 @@ import { NavModel, NavModelItem, NavIndex } from './navModel';
import
{
FolderDTO
,
FolderState
,
FolderInfo
}
from
'./folders'
;
import
{
DashboardState
}
from
'./dashboard'
;
import
{
DashboardAcl
,
OrgRole
,
PermissionLevel
}
from
'./acl'
;
import
{
DataSource
}
from
'./datasources'
;
import
{
ApiKey
,
ApiKeysState
,
NewApiKey
}
from
'./apiKeys'
;
import
{
User
}
from
'./user'
;
import
{
DataSource
,
DataSourcesState
}
from
'./datasources'
;
import
{
PluginMeta
,
Plugin
,
PluginsState
}
from
'./plugins'
;
export
{
...
...
@@ -41,6 +41,7 @@ export {
User
,
Plugin
,
PluginsState
,
DataSourcesState
,
};
export
interface
StoreState
{
...
...
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