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
e0feb726
Commit
e0feb726
authored
Nov 12, 2018
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/data-source-settings-to-react' into develop
parents
a2a44589
7799ad81
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
720 additions
and
451 deletions
+720
-451
.gitignore
+1
-0
public/app/core/services/AngularLoader.ts
+4
-0
public/app/core/services/bridge_srv.ts
+1
-1
public/app/core/utils/connectWithReduxStore.tsx
+1
-1
public/app/features/dashboard/dashgrid/PanelEditor.tsx
+1
-1
public/app/features/dashboard/utils/getPanelMenu.ts
+1
-1
public/app/features/datasources/DataSourceSettings.tsx
+0
-125
public/app/features/datasources/__mocks__/dataSourcesMocks.ts
+3
-0
public/app/features/datasources/settings/BasicSettings.test.tsx
+20
-0
public/app/features/datasources/settings/BasicSettings.tsx
+34
-0
public/app/features/datasources/settings/ButtonRow.test.tsx
+31
-0
public/app/features/datasources/settings/ButtonRow.tsx
+25
-0
public/app/features/datasources/settings/DataSourceSettings.test.tsx
+63
-0
public/app/features/datasources/settings/DataSourceSettings.tsx
+245
-0
public/app/features/datasources/settings/PluginSettings.tsx
+63
-0
public/app/features/datasources/settings/__snapshots__/BasicSettings.test.tsx.snap
+25
-0
public/app/features/datasources/settings/__snapshots__/ButtonRow.test.tsx.snap
+59
-0
public/app/features/datasources/settings/__snapshots__/DataSourceSettings.test.tsx.snap
+0
-0
public/app/features/datasources/state/actions.ts
+54
-13
public/app/features/datasources/state/navModel.ts
+3
-0
public/app/features/datasources/state/reducers.ts
+4
-1
public/app/features/datasources/state/selectors.ts
+9
-1
public/app/features/plugins/__mocks__/pluginMocks.ts
+2
-0
public/app/features/plugins/__snapshots__/PluginList.test.tsx.snap
+6
-0
public/app/features/plugins/all.ts
+0
-1
public/app/features/plugins/ds_dashboards_ctrl.ts
+1
-1
public/app/features/plugins/ds_edit_ctrl.ts
+1
-1
public/app/features/plugins/partials/ds_edit.html
+0
-72
public/app/features/plugins/plugin_component.ts
+8
-0
public/app/features/plugins/plugin_edit_ctrl.ts
+0
-179
public/app/plugins/datasource/cloudwatch/datasource.ts
+3
-8
public/app/routes/ReactContainer.tsx
+1
-1
public/app/routes/routes.ts
+6
-4
public/app/store/configureStore.ts
+3
-4
public/app/store/store.ts
+5
-0
public/app/types/datasources.ts
+3
-0
public/app/types/plugins.ts
+1
-0
public/app/types/series.ts
+1
-0
scripts/webpack/webpack.hot.js
+32
-36
No files found.
.gitignore
View file @
e0feb726
...
...
@@ -76,3 +76,4 @@ debug.test
/devenv/bulk_alerting_dashboards/*.json
/scripts/build/release_publisher/release_publisher
*.patch
public/app/core/services/AngularLoader.ts
View file @
e0feb726
...
...
@@ -4,6 +4,7 @@ import _ from 'lodash';
export
interface
AngularComponent
{
destroy
();
digest
();
}
export
class
AngularLoader
{
...
...
@@ -24,6 +25,9 @@ export class AngularLoader {
scope
.
$destroy
();
compiledElem
.
remove
();
},
digest
:
()
=>
{
scope
.
$digest
();
},
};
}
}
...
...
public/app/core/services/bridge_srv.ts
View file @
e0feb726
import
coreModule
from
'app/core/core_module'
;
import
appEvents
from
'app/core/app_events'
;
import
{
store
}
from
'app/store/
configureS
tore'
;
import
{
store
}
from
'app/store/
s
tore'
;
import
locationUtil
from
'app/core/utils/location_util'
;
import
{
updateLocation
}
from
'app/core/actions'
;
...
...
public/app/core/utils/connectWithReduxStore.tsx
View file @
e0feb726
import
React
from
'react'
;
import
{
connect
}
from
'react-redux'
;
import
{
store
}
from
'../../store/
configureS
tore'
;
import
{
store
}
from
'../../store/
s
tore'
;
export
function
connectWithStore
(
WrappedComponent
,
...
args
)
{
const
ConnectedWrappedComponent
=
connect
(...
args
)(
WrappedComponent
);
...
...
public/app/features/dashboard/dashgrid/PanelEditor.tsx
View file @
e0feb726
...
...
@@ -4,7 +4,7 @@ import classNames from 'classnames';
import
{
QueriesTab
}
from
'./QueriesTab'
;
import
{
VizTypePicker
}
from
'./VizTypePicker'
;
import
{
store
}
from
'app/store/
configureS
tore'
;
import
{
store
}
from
'app/store/
s
tore'
;
import
{
updateLocation
}
from
'app/core/actions'
;
import
{
PanelModel
}
from
'../panel_model'
;
...
...
public/app/features/dashboard/utils/getPanelMenu.ts
View file @
e0feb726
import
{
updateLocation
}
from
'app/core/actions'
;
import
{
store
}
from
'app/store/
configureS
tore'
;
import
{
store
}
from
'app/store/
s
tore'
;
import
{
removePanel
,
duplicatePanel
,
copyPanel
,
editPanelJson
,
sharePanel
}
from
'app/features/dashboard/utils/panel'
;
import
{
PanelModel
}
from
'app/features/dashboard/panel_model'
;
...
...
public/app/features/datasources/DataSourceSettings.tsx
deleted
100644 → 0
View file @
a2a44589
import
React
,
{
PureComponent
}
from
'react'
;
import
{
connect
}
from
'react-redux'
;
import
{
DataSource
,
Plugin
}
from
'app/types'
;
export
interface
Props
{
dataSource
:
DataSource
;
dataSourceMeta
:
Plugin
;
}
interface
State
{
name
:
string
;
}
enum
DataSourceStates
{
Alpha
=
'alpha'
,
Beta
=
'beta'
,
}
export
class
DataSourceSettings
extends
PureComponent
<
Props
,
State
>
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
name
:
props
.
dataSource
.
name
,
};
}
onNameChange
=
event
=>
{
this
.
setState
({
name
:
event
.
target
.
value
,
});
};
onSubmit
=
event
=>
{
event
.
preventDefault
();
console
.
log
(
event
);
};
onDelete
=
event
=>
{
console
.
log
(
event
);
};
isReadyOnly
()
{
return
this
.
props
.
dataSource
.
readOnly
===
true
;
}
shouldRenderInfoBox
()
{
const
{
state
}
=
this
.
props
.
dataSourceMeta
;
return
state
===
DataSourceStates
.
Alpha
||
state
===
DataSourceStates
.
Beta
;
}
getInfoText
()
{
const
{
dataSourceMeta
}
=
this
.
props
;
switch
(
dataSourceMeta
.
state
)
{
case
DataSourceStates
.
Alpha
:
return
(
'This plugin is marked as being in alpha state, which means it is in early development phase and updates'
+
' will include breaking changes.'
);
case
DataSourceStates
.
Beta
:
return
(
'This plugin is marked as being in a beta development state. This means it is in currently in active'
+
' development and could be missing important features.'
);
}
return
null
;
}
render
()
{
const
{
name
}
=
this
.
state
;
return
(
<
div
>
<
h3
className=
"page-sub-heading"
>
Settings
</
h3
>
<
form
onSubmit=
{
this
.
onSubmit
}
>
<
div
className=
"gf-form-group"
>
<
div
className=
"gf-form-inline"
>
<
div
className=
"gf-form max-width-30"
>
<
span
className=
"gf-form-label width-10"
>
Name
</
span
>
<
input
className=
"gf-form-input max-width-23"
type=
"text"
value=
{
name
}
placeholder=
"name"
onChange=
{
this
.
onNameChange
}
required
/>
</
div
>
</
div
>
</
div
>
{
this
.
shouldRenderInfoBox
()
&&
<
div
className=
"grafana-info-box"
>
{
this
.
getInfoText
()
}
</
div
>
}
{
this
.
isReadyOnly
()
&&
(
<
div
className=
"grafana-info-box span8"
>
This datasource was added by config and cannot be modified using the UI. Please contact your server admin
to update this datasource.
</
div
>
)
}
<
div
className=
"gf-form-button-row"
>
<
button
type=
"submit"
className=
"btn btn-success"
disabled=
{
this
.
isReadyOnly
()
}
onClick=
{
this
.
onSubmit
}
>
Save
&
Test
</
button
>
<
button
type=
"submit"
className=
"btn btn-danger"
disabled=
{
this
.
isReadyOnly
()
}
onClick=
{
this
.
onDelete
}
>
Delete
</
button
>
<
a
className=
"btn btn-inverse"
href=
"datasources"
>
Back
</
a
>
</
div
>
</
form
>
</
div
>
);
}
}
function
mapStateToProps
(
state
)
{
return
{
dataSource
:
state
.
dataSources
.
dataSource
,
dataSourceMeta
:
state
.
dataSources
.
dataSourceMeta
,
};
}
export
default
connect
(
mapStateToProps
)(
DataSourceSettings
);
public/app/features/datasources/__mocks__/dataSourcesMocks.ts
View file @
e0feb726
...
...
@@ -29,6 +29,9 @@ export const getMockDataSource = (): DataSource => {
return
{
access
:
''
,
basicAuth
:
false
,
basicAuthUser
:
''
,
basicAuthPassword
:
''
,
withCredentials
:
false
,
database
:
''
,
id
:
13
,
isDefault
:
false
,
...
...
public/app/features/datasources/settings/BasicSettings.test.tsx
0 → 100644
View file @
e0feb726
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
BasicSettings
,
{
Props
}
from
'./BasicSettings'
;
const
setup
=
()
=>
{
const
props
:
Props
=
{
dataSourceName
:
'Graphite'
,
onChange
:
jest
.
fn
(),
};
return
shallow
(<
BasicSettings
{
...
props
}
/>);
};
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
wrapper
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
});
public/app/features/datasources/settings/BasicSettings.tsx
0 → 100644
View file @
e0feb726
import
React
,
{
SFC
}
from
'react'
;
import
{
Label
}
from
'app/core/components/Label/Label'
;
export
interface
Props
{
dataSourceName
:
string
;
onChange
:
(
name
:
string
)
=>
void
;
}
const
BasicSettings
:
SFC
<
Props
>
=
({
dataSourceName
,
onChange
})
=>
{
return
(
<
div
className=
"gf-form-group"
>
<
div
className=
"gf-form max-width-30"
>
<
Label
tooltip=
{
'The name is used when you select the data source in panels. The Default data source is'
+
'preselected in new panels.'
}
>
Name
</
Label
>
<
input
className=
"gf-form-input max-width-23"
type=
"text"
value=
{
dataSourceName
}
placeholder=
"Name"
onChange=
{
event
=>
onChange
(
event
.
target
.
value
)
}
required
/>
</
div
>
</
div
>
);
};
export
default
BasicSettings
;
public/app/features/datasources/settings/ButtonRow.test.tsx
0 → 100644
View file @
e0feb726
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
ButtonRow
,
{
Props
}
from
'./ButtonRow'
;
const
setup
=
(
propOverrides
?:
object
)
=>
{
const
props
:
Props
=
{
isReadOnly
:
true
,
onSubmit
:
jest
.
fn
(),
onDelete
:
jest
.
fn
(),
};
Object
.
assign
(
props
,
propOverrides
);
return
shallow
(<
ButtonRow
{
...
props
}
/>);
};
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
wrapper
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render with buttons enabled'
,
()
=>
{
const
wrapper
=
setup
({
isReadOnly
:
false
,
});
expect
(
wrapper
).
toMatchSnapshot
();
});
});
public/app/features/datasources/settings/ButtonRow.tsx
0 → 100644
View file @
e0feb726
import
React
,
{
SFC
}
from
'react'
;
export
interface
Props
{
isReadOnly
:
boolean
;
onDelete
:
()
=>
void
;
onSubmit
:
(
event
)
=>
void
;
}
const
ButtonRow
:
SFC
<
Props
>
=
({
isReadOnly
,
onDelete
,
onSubmit
})
=>
{
return
(
<
div
className=
"gf-form-button-row"
>
<
button
type=
"submit"
className=
"btn btn-success"
disabled=
{
isReadOnly
}
onClick=
{
event
=>
onSubmit
(
event
)
}
>
Save
&
Test
</
button
>
<
button
type=
"submit"
className=
"btn btn-danger"
disabled=
{
isReadOnly
}
onClick=
{
onDelete
}
>
Delete
</
button
>
<
a
className=
"btn btn-inverse"
href=
"/datasources"
>
Back
</
a
>
</
div
>
);
};
export
default
ButtonRow
;
public/app/features/datasources/settings/DataSourceSettings.test.tsx
0 → 100644
View file @
e0feb726
import
React
from
'react'
;
import
{
shallow
}
from
'enzyme'
;
import
{
DataSourceSettings
,
Props
}
from
'./DataSourceSettings'
;
import
{
DataSource
,
NavModel
}
from
'../../../types'
;
import
{
getMockDataSource
}
from
'../__mocks__/dataSourcesMocks'
;
import
{
getMockPlugin
}
from
'../../plugins/__mocks__/pluginMocks'
;
const
setup
=
(
propOverrides
?:
object
)
=>
{
const
props
:
Props
=
{
navModel
:
{}
as
NavModel
,
dataSource
:
getMockDataSource
(),
dataSourceMeta
:
getMockPlugin
(),
pageId
:
1
,
deleteDataSource
:
jest
.
fn
(),
loadDataSource
:
jest
.
fn
(),
setDataSourceName
:
jest
.
fn
(),
updateDataSource
:
jest
.
fn
(),
};
Object
.
assign
(
props
,
propOverrides
);
return
shallow
(<
DataSourceSettings
{
...
props
}
/>);
};
describe
(
'Render'
,
()
=>
{
it
(
'should render component'
,
()
=>
{
const
wrapper
=
setup
();
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render loader'
,
()
=>
{
const
wrapper
=
setup
({
dataSource
:
{}
as
DataSource
,
});
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render beta info text'
,
()
=>
{
const
wrapper
=
setup
({
dataSourceMeta
:
{
...
getMockPlugin
(),
state
:
'beta'
},
});
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render alpha info text'
,
()
=>
{
const
wrapper
=
setup
({
dataSourceMeta
:
{
...
getMockPlugin
(),
state
:
'alpha'
},
});
expect
(
wrapper
).
toMatchSnapshot
();
});
it
(
'should render is ready only message'
,
()
=>
{
const
wrapper
=
setup
({
dataSource
:
{
...
getMockDataSource
(),
readOnly
:
true
},
});
expect
(
wrapper
).
toMatchSnapshot
();
});
});
public/app/features/datasources/settings/DataSourceSettings.tsx
0 → 100644
View file @
e0feb726
import
React
,
{
PureComponent
}
from
'react'
;
import
{
hot
}
from
'react-hot-loader'
;
import
{
connect
}
from
'react-redux'
;
import
PageHeader
from
'app/core/components/PageHeader/PageHeader'
;
import
PageLoader
from
'app/core/components/PageLoader/PageLoader'
;
import
PluginSettings
from
'./PluginSettings'
;
import
BasicSettings
from
'./BasicSettings'
;
import
ButtonRow
from
'./ButtonRow'
;
import
appEvents
from
'app/core/app_events'
;
import
{
getBackendSrv
}
from
'app/core/services/backend_srv'
;
import
{
getDatasourceSrv
}
from
'app/features/plugins/datasource_srv'
;
import
{
getDataSource
,
getDataSourceMeta
}
from
'../state/selectors'
;
import
{
deleteDataSource
,
loadDataSource
,
setDataSourceName
,
updateDataSource
}
from
'../state/actions'
;
import
{
getNavModel
}
from
'app/core/selectors/navModel'
;
import
{
getRouteParamsId
}
from
'app/core/selectors/location'
;
import
{
DataSource
,
NavModel
,
Plugin
}
from
'app/types/'
;
import
{
getDataSourceLoadingNav
}
from
'../state/navModel'
;
export
interface
Props
{
navModel
:
NavModel
;
dataSource
:
DataSource
;
dataSourceMeta
:
Plugin
;
pageId
:
number
;
deleteDataSource
:
typeof
deleteDataSource
;
loadDataSource
:
typeof
loadDataSource
;
setDataSourceName
:
typeof
setDataSourceName
;
updateDataSource
:
typeof
updateDataSource
;
}
interface
State
{
dataSource
:
DataSource
;
isTesting
?:
boolean
;
testingMessage
?:
string
;
testingStatus
?:
string
;
}
enum
DataSourceStates
{
Alpha
=
'alpha'
,
Beta
=
'beta'
,
}
export
class
DataSourceSettings
extends
PureComponent
<
Props
,
State
>
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
dataSource
:
{}
as
DataSource
,
};
}
async
componentDidMount
()
{
const
{
loadDataSource
,
pageId
}
=
this
.
props
;
await
loadDataSource
(
pageId
);
}
onSubmit
=
async
event
=>
{
event
.
preventDefault
();
await
this
.
props
.
updateDataSource
({
...
this
.
state
.
dataSource
,
name
:
this
.
props
.
dataSource
.
name
});
this
.
testDataSource
();
};
onDelete
=
()
=>
{
appEvents
.
emit
(
'confirm-modal'
,
{
title
:
'Delete'
,
text
:
'Are you sure you want to delete this data source?'
,
yesText
:
'Delete'
,
icon
:
'fa-trash'
,
onConfirm
:
()
=>
{
this
.
confirmDelete
();
},
});
};
confirmDelete
=
()
=>
{
this
.
props
.
deleteDataSource
();
};
onModelChange
=
dataSource
=>
{
this
.
setState
({
dataSource
:
dataSource
,
});
};
isReadOnly
()
{
return
this
.
props
.
dataSource
.
readOnly
===
true
;
}
shouldRenderInfoBox
()
{
const
{
state
}
=
this
.
props
.
dataSourceMeta
;
return
state
===
DataSourceStates
.
Alpha
||
state
===
DataSourceStates
.
Beta
;
}
getInfoText
()
{
const
{
dataSourceMeta
}
=
this
.
props
;
switch
(
dataSourceMeta
.
state
)
{
case
DataSourceStates
.
Alpha
:
return
(
'This plugin is marked as being in alpha state, which means it is in early development phase and updates'
+
' will include breaking changes.'
);
case
DataSourceStates
.
Beta
:
return
(
'This plugin is marked as being in a beta development state. This means it is in currently in active'
+
' development and could be missing important features.'
);
}
return
null
;
}
renderIsReadOnlyMessage
()
{
return
(
<
div
className=
"grafana-info-box span8"
>
This datasource was added by config and cannot be modified using the UI. Please contact your server admin to
update this datasource.
</
div
>
);
}
async
testDataSource
()
{
const
dsApi
=
await
getDatasourceSrv
().
get
(
this
.
state
.
dataSource
.
name
);
if
(
!
dsApi
.
testDatasource
)
{
return
;
}
this
.
setState
({
isTesting
:
true
,
testingMessage
:
'Testing...'
,
testingStatus
:
'info'
});
getBackendSrv
().
withNoBackendCache
(
async
()
=>
{
try
{
const
result
=
await
dsApi
.
testDatasource
();
this
.
setState
({
isTesting
:
false
,
testingStatus
:
result
.
status
,
testingMessage
:
result
.
message
,
});
}
catch
(
err
)
{
let
message
=
''
;
if
(
err
.
statusText
)
{
message
=
'HTTP Error '
+
err
.
statusText
;
}
else
{
message
=
err
.
message
;
}
this
.
setState
({
isTesting
:
false
,
testingStatus
:
'error'
,
testingMessage
:
message
,
});
}
});
}
render
()
{
const
{
dataSource
,
dataSourceMeta
,
navModel
}
=
this
.
props
;
const
{
testingMessage
,
testingStatus
}
=
this
.
state
;
return
(
<
div
>
<
PageHeader
model=
{
navModel
}
/>
{
Object
.
keys
(
dataSource
).
length
===
0
?
(
<
PageLoader
pageName=
"Data source settings"
/>
)
:
(
<
div
className=
"page-container page-body"
>
<
div
>
<
form
onSubmit=
{
this
.
onSubmit
}
>
<
BasicSettings
dataSourceName=
{
this
.
props
.
dataSource
.
name
}
onChange=
{
name
=>
this
.
props
.
setDataSourceName
(
name
)
}
/>
{
this
.
shouldRenderInfoBox
()
&&
<
div
className=
"grafana-info-box"
>
{
this
.
getInfoText
()
}
</
div
>
}
{
this
.
isReadOnly
()
&&
this
.
renderIsReadOnlyMessage
()
}
{
dataSourceMeta
.
module
&&
(
<
PluginSettings
dataSource=
{
dataSource
}
dataSourceMeta=
{
dataSourceMeta
}
onModelChange=
{
this
.
onModelChange
}
/>
)
}
<
div
className=
"gf-form-group section"
>
{
testingMessage
&&
(
<
div
className=
{
`alert-${testingStatus} alert`
}
>
<
div
className=
"alert-icon"
>
{
testingStatus
===
'error'
?
(
<
i
className=
"fa fa-exclamation-triangle"
/>
)
:
(
<
i
className=
"fa fa-check"
/>
)
}
</
div
>
<
div
className=
"alert-body"
>
<
div
className=
"alert-title"
>
{
testingMessage
}
</
div
>
</
div
>
</
div
>
)
}
</
div
>
<
ButtonRow
onSubmit=
{
event
=>
this
.
onSubmit
(
event
)
}
isReadOnly=
{
this
.
isReadOnly
()
}
onDelete=
{
this
.
onDelete
}
/>
</
form
>
</
div
>
</
div
>
)
}
</
div
>
);
}
}
function
mapStateToProps
(
state
)
{
const
pageId
=
getRouteParamsId
(
state
.
location
);
const
dataSource
=
getDataSource
(
state
.
dataSources
,
pageId
);
return
{
navModel
:
getNavModel
(
state
.
navIndex
,
`datasource-settings-
${
pageId
}
`
,
getDataSourceLoadingNav
(
'settings'
)),
dataSource
:
getDataSource
(
state
.
dataSources
,
pageId
),
dataSourceMeta
:
getDataSourceMeta
(
state
.
dataSources
,
dataSource
.
type
),
pageId
:
pageId
,
};
}
const
mapDispatchToProps
=
{
deleteDataSource
,
loadDataSource
,
setDataSourceName
,
updateDataSource
,
};
export
default
hot
(
module
)(
connect
(
mapStateToProps
,
mapDispatchToProps
)(
DataSourceSettings
));
public/app/features/datasources/settings/PluginSettings.tsx
0 → 100644
View file @
e0feb726
import
React
,
{
PureComponent
}
from
'react'
;
import
_
from
'lodash'
;
import
{
DataSource
,
Plugin
}
from
'app/types/'
;
import
{
getAngularLoader
,
AngularComponent
}
from
'app/core/services/AngularLoader'
;
export
interface
Props
{
dataSource
:
DataSource
;
dataSourceMeta
:
Plugin
;
onModelChange
:
(
dataSource
:
DataSource
)
=>
void
;
}
export
class
PluginSettings
extends
PureComponent
<
Props
>
{
element
:
any
;
component
:
AngularComponent
;
scopeProps
:
{
ctrl
:
{
datasourceMeta
:
Plugin
;
current
:
DataSource
};
onModelChanged
:
(
dataSource
:
DataSource
)
=>
void
;
};
constructor
(
props
)
{
super
(
props
);
this
.
scopeProps
=
{
ctrl
:
{
datasourceMeta
:
props
.
dataSourceMeta
,
current
:
_
.
cloneDeep
(
props
.
dataSource
)
},
onModelChanged
:
this
.
onModelChanged
,
};
}
componentDidMount
()
{
if
(
!
this
.
element
)
{
return
;
}
const
loader
=
getAngularLoader
();
const
template
=
'<plugin-component type="datasource-config-ctrl" />'
;
this
.
component
=
loader
.
load
(
this
.
element
,
this
.
scopeProps
,
template
);
}
componentDidUpdate
(
prevProps
)
{
if
(
this
.
props
.
dataSource
!==
prevProps
.
dataSource
)
{
this
.
scopeProps
.
ctrl
.
current
=
_
.
cloneDeep
(
this
.
props
.
dataSource
);
this
.
component
.
digest
();
}
}
componentWillUnmount
()
{
if
(
this
.
component
)
{
this
.
component
.
destroy
();
}
}
onModelChanged
=
(
dataSource
:
DataSource
)
=>
{
this
.
props
.
onModelChange
(
dataSource
);
};
render
()
{
return
<
div
ref=
{
element
=>
(
this
.
element
=
element
)
}
/>;
}
}
export
default
PluginSettings
;
public/app/features/datasources/settings/__snapshots__/BasicSettings.test.tsx.snap
0 → 100644
View file @
e0feb726
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<div
className="gf-form-group"
>
<div
className="gf-form max-width-30"
>
<Component
tooltip="The name is used when you select the data source in panels. The Default data source ispreselected in new panels."
>
Name
</Component>
<input
className="gf-form-input max-width-23"
onChange={[Function]}
placeholder="Name"
required={true}
type="text"
value="Graphite"
/>
</div>
</div>
`;
public/app/features/datasources/settings/__snapshots__/ButtonRow.test.tsx.snap
0 → 100644
View file @
e0feb726
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<div
className="gf-form-button-row"
>
<button
className="btn btn-success"
disabled={true}
onClick={[Function]}
type="submit"
>
Save & Test
</button>
<button
className="btn btn-danger"
disabled={true}
onClick={[MockFunction]}
type="submit"
>
Delete
</button>
<a
className="btn btn-inverse"
href="/datasources"
>
Back
</a>
</div>
`;
exports[`Render should render with buttons enabled 1`] = `
<div
className="gf-form-button-row"
>
<button
className="btn btn-success"
disabled={false}
onClick={[Function]}
type="submit"
>
Save & Test
</button>
<button
className="btn btn-danger"
disabled={false}
onClick={[MockFunction]}
type="submit"
>
Delete
</button>
<a
className="btn btn-inverse"
href="/datasources"
>
Back
</a>
</div>
`;
public/app/features/datasources/settings/__snapshots__/DataSourceSettings.test.tsx.snap
0 → 100644
View file @
e0feb726
This diff is collapsed.
Click to expand it.
public/app/features/datasources/state/actions.ts
View file @
e0feb726
import
{
ThunkAction
}
from
'redux-thunk'
;
import
{
DataSource
,
Plugin
,
StoreState
}
from
'app/types'
;
import
{
getBackendSrv
}
from
'../../../core/services/backend_srv'
;
import
{
LayoutMode
}
from
'../../../core/components/LayoutSelector/LayoutSelector'
;
import
{
updateLocation
,
updateNavIndex
,
UpdateNavIndexAction
}
from
'../../../core/actions'
;
import
{
UpdateLocationAction
}
from
'../../../core/actions/location'
;
import
config
from
'../../../core/config'
;
import
{
getBackendSrv
}
from
'app/core/services/backend_srv'
;
import
{
getDatasourceSrv
}
from
'app/features/plugins/datasource_srv'
;
import
{
LayoutMode
}
from
'app/core/components/LayoutSelector/LayoutSelector'
;
import
{
updateLocation
,
updateNavIndex
,
UpdateNavIndexAction
}
from
'app/core/actions'
;
import
{
UpdateLocationAction
}
from
'app/core/actions/location'
;
import
{
buildNavModel
}
from
'./navModel'
;
import
{
DataSource
,
Plugin
,
StoreState
}
from
'app/types'
;
export
enum
ActionTypes
{
LoadDataSources
=
'LOAD_DATA_SOURCES'
,
...
...
@@ -14,43 +16,49 @@ export enum ActionTypes {
SetDataSourcesSearchQuery
=
'SET_DATA_SOURCES_SEARCH_QUERY'
,
SetDataSourcesLayoutMode
=
'SET_DATA_SOURCES_LAYOUT_MODE'
,
SetDataSourceTypeSearchQuery
=
'SET_DATA_SOURCE_TYPE_SEARCH_QUERY'
,
SetDataSourceName
=
'SET_DATA_SOURCE_NAME'
,
}
export
interface
LoadDataSourcesAction
{
interface
LoadDataSourcesAction
{
type
:
ActionTypes
.
LoadDataSources
;
payload
:
DataSource
[];
}
export
interface
SetDataSourcesSearchQueryAction
{
interface
SetDataSourcesSearchQueryAction
{
type
:
ActionTypes
.
SetDataSourcesSearchQuery
;
payload
:
string
;
}
export
interface
SetDataSourcesLayoutModeAction
{
interface
SetDataSourcesLayoutModeAction
{
type
:
ActionTypes
.
SetDataSourcesLayoutMode
;
payload
:
LayoutMode
;
}
export
interface
LoadDataSourceTypesAction
{
interface
LoadDataSourceTypesAction
{
type
:
ActionTypes
.
LoadDataSourceTypes
;
payload
:
Plugin
[];
}
export
interface
SetDataSourceTypeSearchQueryAction
{
interface
SetDataSourceTypeSearchQueryAction
{
type
:
ActionTypes
.
SetDataSourceTypeSearchQuery
;
payload
:
string
;
}
export
interface
LoadDataSourceAction
{
interface
LoadDataSourceAction
{
type
:
ActionTypes
.
LoadDataSource
;
payload
:
DataSource
;
}
export
interface
LoadDataSourceMetaAction
{
interface
LoadDataSourceMetaAction
{
type
:
ActionTypes
.
LoadDataSourceMeta
;
payload
:
Plugin
;
}
interface
SetDataSourceNameAction
{
type
:
ActionTypes
.
SetDataSourceName
;
payload
:
string
;
}
const
dataSourcesLoaded
=
(
dataSources
:
DataSource
[]):
LoadDataSourcesAction
=>
({
type
:
ActionTypes
.
LoadDataSources
,
payload
:
dataSources
,
...
...
@@ -86,6 +94,11 @@ export const setDataSourceTypeSearchQuery = (query: string): SetDataSourceTypeSe
payload
:
query
,
});
export
const
setDataSourceName
=
(
name
:
string
)
=>
({
type
:
ActionTypes
.
SetDataSourceName
,
payload
:
name
,
});
export
type
Action
=
|
LoadDataSourcesAction
|
SetDataSourcesSearchQueryAction
...
...
@@ -95,7 +108,8 @@ export type Action =
|
SetDataSourceTypeSearchQueryAction
|
LoadDataSourceAction
|
UpdateNavIndexAction
|
LoadDataSourceMetaAction
;
|
LoadDataSourceMetaAction
|
SetDataSourceNameAction
;
type
ThunkResult
<
R
>
=
ThunkAction
<
R
,
StoreState
,
undefined
,
Action
>
;
...
...
@@ -145,6 +159,23 @@ export function loadDataSourceTypes(): ThunkResult<void> {
};
}
export
function
updateDataSource
(
dataSource
:
DataSource
):
ThunkResult
<
void
>
{
return
async
dispatch
=>
{
await
getBackendSrv
().
put
(
`/api/datasources/
${
dataSource
.
id
}
`
,
dataSource
);
await
updateFrontendSettings
();
return
dispatch
(
loadDataSource
(
dataSource
.
id
));
};
}
export
function
deleteDataSource
():
ThunkResult
<
void
>
{
return
async
(
dispatch
,
getStore
)
=>
{
const
dataSource
=
getStore
().
dataSources
.
dataSource
;
await
getBackendSrv
().
delete
(
`/api/datasources/
${
dataSource
.
id
}
`
);
dispatch
(
updateLocation
({
path
:
'/datasources'
}));
};
}
export
function
nameExits
(
dataSources
,
name
)
{
return
(
dataSources
.
filter
(
dataSource
=>
{
...
...
@@ -173,6 +204,16 @@ export function findNewName(dataSources, name) {
return
name
;
}
function
updateFrontendSettings
()
{
return
getBackendSrv
()
.
get
(
'/api/frontend/settings'
)
.
then
(
settings
=>
{
config
.
datasources
=
settings
.
datasources
;
config
.
defaultDatasource
=
settings
.
defaultDatasource
;
getDatasourceSrv
().
init
();
});
}
function
nameHasSuffix
(
name
)
{
return
name
.
endsWith
(
'-'
,
name
.
length
-
1
);
}
...
...
public/app/features/datasources/state/navModel.ts
View file @
e0feb726
...
...
@@ -48,6 +48,9 @@ export function getDataSourceLoadingNav(pageName: string): NavModel {
{
access
:
''
,
basicAuth
:
false
,
basicAuthUser
:
''
,
basicAuthPassword
:
''
,
withCredentials
:
false
,
database
:
''
,
id
:
1
,
isDefault
:
false
,
...
...
public/app/features/datasources/state/reducers.ts
View file @
e0feb726
...
...
@@ -10,8 +10,8 @@ const initialState: DataSourcesState = {
dataSourcesCount
:
0
,
dataSourceTypes
:
[]
as
Plugin
[],
dataSourceTypeSearchQuery
:
''
,
dataSourceMeta
:
{}
as
Plugin
,
hasFetched
:
false
,
dataSourceMeta
:
{}
as
Plugin
,
};
export
const
dataSourcesReducer
=
(
state
=
initialState
,
action
:
Action
):
DataSourcesState
=>
{
...
...
@@ -36,6 +36,9 @@ export const dataSourcesReducer = (state = initialState, action: Action): DataSo
case
ActionTypes
.
LoadDataSourceMeta
:
return
{
...
state
,
dataSourceMeta
:
action
.
payload
};
case
ActionTypes
.
SetDataSourceName
:
return
{
...
state
,
dataSource
:
{
...
state
.
dataSource
,
name
:
action
.
payload
}
};
}
return
state
;
...
...
public/app/features/datasources/state/selectors.ts
View file @
e0feb726
...
...
@@ -20,7 +20,15 @@ export const getDataSource = (state, dataSourceId): DataSource | null => {
if
(
state
.
dataSource
.
id
===
parseInt
(
dataSourceId
,
10
))
{
return
state
.
dataSource
;
}
return
null
;
return
{}
as
DataSource
;
};
export
const
getDataSourceMeta
=
(
state
,
type
):
Plugin
=>
{
if
(
state
.
dataSourceMeta
.
id
===
type
)
{
return
state
.
dataSourceMeta
;
}
return
{}
as
Plugin
;
};
export
const
getDataSourcesSearchQuery
=
state
=>
state
.
searchQuery
;
...
...
public/app/features/plugins/__mocks__/pluginMocks.ts
View file @
e0feb726
...
...
@@ -26,6 +26,7 @@ export const getMockPlugins = (amount: number): Plugin[] => {
pinned
:
false
,
state
:
''
,
type
:
''
,
module
:
{},
});
}
...
...
@@ -55,5 +56,6 @@ export const getMockPlugin = () => {
pinned
:
false
,
state
:
''
,
type
:
''
,
module
:
{},
};
};
public/app/features/plugins/__snapshots__/PluginList.test.tsx.snap
View file @
e0feb726
...
...
@@ -33,6 +33,7 @@ exports[`Render should render component 1`] = `
"version": "1",
},
"latestVersion": "1.0",
"module": Object {},
"name": "pretty cool plugin-0",
"pinned": false,
"state": "",
...
...
@@ -66,6 +67,7 @@ exports[`Render should render component 1`] = `
"version": "1",
},
"latestVersion": "1.1",
"module": Object {},
"name": "pretty cool plugin-1",
"pinned": false,
"state": "",
...
...
@@ -99,6 +101,7 @@ exports[`Render should render component 1`] = `
"version": "1",
},
"latestVersion": "1.2",
"module": Object {},
"name": "pretty cool plugin-2",
"pinned": false,
"state": "",
...
...
@@ -132,6 +135,7 @@ exports[`Render should render component 1`] = `
"version": "1",
},
"latestVersion": "1.3",
"module": Object {},
"name": "pretty cool plugin-3",
"pinned": false,
"state": "",
...
...
@@ -165,6 +169,7 @@ exports[`Render should render component 1`] = `
"version": "1",
},
"latestVersion": "1.4",
"module": Object {},
"name": "pretty cool plugin-4",
"pinned": false,
"state": "",
...
...
@@ -198,6 +203,7 @@ exports[`Render should render component 1`] = `
"version": "1",
},
"latestVersion": "1.5",
"module": Object {},
"name": "pretty cool plugin-5",
"pinned": false,
"state": "",
...
...
public/app/features/plugins/all.ts
View file @
e0feb726
import
'./plugin_edit_ctrl'
;
import
'./plugin_page_ctrl'
;
import
'./import_list/import_list'
;
import
'./ds_edit_ctrl'
;
...
...
public/app/features/plugins/ds_dashboards_ctrl.ts
View file @
e0feb726
import
{
coreModule
}
from
'app/core/core'
;
import
{
store
}
from
'app/store/
configureS
tore'
;
import
{
store
}
from
'app/store/
s
tore'
;
import
{
getNavModel
}
from
'app/core/selectors/navModel'
;
import
{
buildNavModel
}
from
'./state/navModel'
;
...
...
public/app/features/plugins/ds_edit_ctrl.ts
View file @
e0feb726
import
_
from
'lodash'
;
import
config
from
'app/core/config'
;
import
{
coreModule
,
appEvents
}
from
'app/core/core'
;
import
{
store
}
from
'app/store/
configureS
tore'
;
import
{
store
}
from
'app/store/
s
tore'
;
import
{
getNavModel
}
from
'app/core/selectors/navModel'
;
import
{
buildNavModel
}
from
'./state/navModel'
;
...
...
public/app/features/plugins/partials/ds_edit.html
deleted
100644 → 0
View file @
a2a44589
<page-header
model=
"ctrl.navModel"
></page-header>
<div
class=
"page-container page-body"
>
<h3
class=
"page-sub-heading"
>
Settings
</h3>
<form
name=
"ctrl.editForm"
ng-if=
"ctrl.current"
>
<div
class=
"gf-form-group"
>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form max-width-30"
>
<span
class=
"gf-form-label width-10"
>
Name
</span>
<input
class=
"gf-form-input max-width-23"
type=
"text"
ng-model=
"ctrl.current.name"
placeholder=
"name"
required
>
<info-popover
offset=
"0px -135px"
mode=
"right-absolute"
>
The name is used when you select the data source in panels.
The
<em>
Default
</em>
data source is preselected in new
panels.
</info-popover>
</div>
<gf-form-switch
class=
"gf-form"
label=
"Default"
checked=
"ctrl.current.isDefault"
switch-class=
"max-width-6"
></gf-form-switch>
</div>
</div>
<div
class=
"grafana-info-box"
ng-if=
"ctrl.datasourceMeta.state === 'alpha'"
>
This plugin is marked as being in alpha state, which means it is in early development phase and
updates will include breaking changes.
</div>
<div
class=
"grafana-info-box"
ng-if=
"ctrl.datasourceMeta.state === 'beta'"
>
This plugin is marked as being in a beta development state. This means it is in currently in active development and could be
missing important features.
</div>
<rebuild-on-change
property=
"ctrl.datasourceMeta.id"
>
<plugin-component
type=
"datasource-config-ctrl"
>
</plugin-component>
</rebuild-on-change>
<div
ng-if=
"ctrl.hasDashboards"
>
<h3
class=
"section-heading"
>
Bundled Plugin Dashboards
</h3>
<div
class=
"section"
>
<dashboard-import-list
plugin=
"ctrl.datasourceMeta"
datasource=
"ctrl.current"
></dashboard-import-list>
</div>
</div>
<div
ng-if=
"ctrl.testing"
class=
"gf-form-group section"
>
<h5
ng-show=
"!ctrl.testing.done"
>
Testing....
<i
class=
"fa fa-spiner fa-spin"
></i></h5>
<div
class=
"alert-{{ctrl.testing.status}} alert"
ng-show=
"ctrl.testing.done"
>
<div
class=
"alert-icon"
>
<i
class=
"fa fa-exclamation-triangle"
ng-show=
"ctrl.testing.status === 'error'"
></i>
<i
class=
"fa fa-check"
ng-show=
"ctrl.testing.status !== 'error'"
></i>
</div>
<div
class=
"alert-body"
>
<div
class=
"alert-title"
>
{{ctrl.testing.message}}
</div>
</div>
</div>
</div>
<div
class=
"grafana-info-box span8"
ng-if=
"ctrl.current.readOnly"
>
This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.
</div>
<div
class=
"gf-form-button-row"
>
<button
type=
"submit"
class=
"btn btn-success"
ng-disabled=
"ctrl.current.readOnly"
ng-click=
"ctrl.saveChanges()"
>
Save
&
Test
</button>
<button
type=
"submit"
class=
"btn btn-danger"
ng-disabled=
"ctrl.current.readOnly"
ng-show=
"!ctrl.isNew"
ng-click=
"ctrl.delete()"
>
Delete
</button>
<a
class=
"btn btn-inverse"
href=
"datasources"
>
Back
</a>
</div>
<br
/>
<br
/>
<br
/>
</form>
</div>
public/app/features/plugins/plugin_component.ts
View file @
e0feb726
...
...
@@ -149,6 +149,14 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $
return
{
notFound
:
true
};
}
scope
.
$watch
(
'ctrl.current'
,
()
=>
{
scope
.
onModelChanged
(
scope
.
ctrl
.
current
);
},
true
);
return
{
baseUrl
:
dsMeta
.
baseUrl
,
name
:
'ds-config-'
+
dsMeta
.
id
,
...
...
public/app/features/plugins/plugin_edit_ctrl.ts
deleted
100644 → 0
View file @
a2a44589
import
angular
from
'angular'
;
import
_
from
'lodash'
;
import
Remarkable
from
'remarkable'
;
export
class
PluginEditCtrl
{
model
:
any
;
pluginIcon
:
string
;
pluginId
:
any
;
includes
:
any
;
readmeHtml
:
any
;
includedDatasources
:
any
;
tab
:
string
;
navModel
:
any
;
hasDashboards
:
any
;
preUpdateHook
:
()
=>
any
;
postUpdateHook
:
()
=>
any
;
/** @ngInject */
constructor
(
private
$scope
,
private
$rootScope
,
private
backendSrv
,
private
$sce
,
private
$routeParams
,
navModelSrv
)
{
this
.
pluginId
=
$routeParams
.
pluginId
;
this
.
preUpdateHook
=
()
=>
Promise
.
resolve
();
this
.
postUpdateHook
=
()
=>
Promise
.
resolve
();
this
.
init
();
}
setNavModel
(
model
)
{
let
defaultTab
=
'readme'
;
this
.
navModel
=
{
main
:
{
img
:
model
.
info
.
logos
.
large
,
subTitle
:
model
.
info
.
author
.
name
,
url
:
''
,
text
:
model
.
name
,
breadcrumbs
:
[{
title
:
'Plugins'
,
url
:
'plugins'
}],
children
:
[
{
icon
:
'fa fa-fw fa-file-text-o'
,
id
:
'readme'
,
text
:
'Readme'
,
url
:
`plugins/
${
this
.
model
.
id
}
/edit?tab=readme`
,
},
],
},
};
if
(
model
.
type
===
'app'
)
{
this
.
navModel
.
main
.
children
.
push
({
icon
:
'gicon gicon-cog'
,
id
:
'config'
,
text
:
'Config'
,
url
:
`plugins/
${
this
.
model
.
id
}
/edit?tab=config`
,
});
const
hasDashboards
=
_
.
find
(
model
.
includes
,
{
type
:
'dashboard'
});
if
(
hasDashboards
)
{
this
.
navModel
.
main
.
children
.
push
({
icon
:
'gicon gicon-dashboard'
,
id
:
'dashboards'
,
text
:
'Dashboards'
,
url
:
`plugins/
${
this
.
model
.
id
}
/edit?tab=dashboards`
,
});
}
defaultTab
=
'config'
;
}
this
.
tab
=
this
.
$routeParams
.
tab
||
defaultTab
;
for
(
const
tab
of
this
.
navModel
.
main
.
children
)
{
if
(
tab
.
id
===
this
.
tab
)
{
tab
.
active
=
true
;
}
}
}
init
()
{
return
this
.
backendSrv
.
get
(
`/api/plugins/
${
this
.
pluginId
}
/settings`
).
then
(
result
=>
{
this
.
model
=
result
;
this
.
pluginIcon
=
this
.
getPluginIcon
(
this
.
model
.
type
);
this
.
model
.
dependencies
.
plugins
.
forEach
(
plug
=>
{
plug
.
icon
=
this
.
getPluginIcon
(
plug
.
type
);
});
this
.
includes
=
_
.
map
(
result
.
includes
,
plug
=>
{
plug
.
icon
=
this
.
getPluginIcon
(
plug
.
type
);
return
plug
;
});
this
.
setNavModel
(
this
.
model
);
return
this
.
initReadme
();
});
}
initReadme
()
{
return
this
.
backendSrv
.
get
(
`/api/plugins/
${
this
.
pluginId
}
/markdown/readme`
).
then
(
res
=>
{
const
md
=
new
Remarkable
({
linkify
:
true
,
});
this
.
readmeHtml
=
this
.
$sce
.
trustAsHtml
(
md
.
render
(
res
));
});
}
getPluginIcon
(
type
)
{
switch
(
type
)
{
case
'datasource'
:
return
'icon-gf icon-gf-datasources'
;
case
'panel'
:
return
'icon-gf icon-gf-panel'
;
case
'app'
:
return
'icon-gf icon-gf-apps'
;
case
'page'
:
return
'icon-gf icon-gf-endpoint-tiny'
;
case
'dashboard'
:
return
'icon-gf icon-gf-dashboard'
;
default
:
return
'icon-gf icon-gf-apps'
;
}
}
update
()
{
this
.
preUpdateHook
()
.
then
(()
=>
{
const
updateCmd
=
_
.
extend
(
{
enabled
:
this
.
model
.
enabled
,
pinned
:
this
.
model
.
pinned
,
jsonData
:
this
.
model
.
jsonData
,
secureJsonData
:
this
.
model
.
secureJsonData
,
},
{}
);
return
this
.
backendSrv
.
post
(
`/api/plugins/
${
this
.
pluginId
}
/settings`
,
updateCmd
);
})
.
then
(
this
.
postUpdateHook
)
.
then
(
res
=>
{
window
.
location
.
href
=
window
.
location
.
href
;
});
}
importDashboards
()
{
return
Promise
.
resolve
();
}
setPreUpdateHook
(
callback
:
()
=>
any
)
{
this
.
preUpdateHook
=
callback
;
}
setPostUpdateHook
(
callback
:
()
=>
any
)
{
this
.
postUpdateHook
=
callback
;
}
updateAvailable
()
{
const
modalScope
=
this
.
$scope
.
$new
(
true
);
modalScope
.
plugin
=
this
.
model
;
this
.
$rootScope
.
appEvent
(
'show-modal'
,
{
src
:
'public/app/features/plugins/partials/update_instructions.html'
,
scope
:
modalScope
,
});
}
enable
()
{
this
.
model
.
enabled
=
true
;
this
.
model
.
pinned
=
true
;
this
.
update
();
}
disable
()
{
this
.
model
.
enabled
=
false
;
this
.
model
.
pinned
=
false
;
this
.
update
();
}
}
angular
.
module
(
'grafana.controllers'
).
controller
(
'PluginEditCtrl'
,
PluginEditCtrl
);
public/app/plugins/datasource/cloudwatch/datasource.ts
View file @
e0feb726
...
...
@@ -362,14 +362,9 @@ export default class CloudWatchDatasource {
const
metricName
=
'EstimatedCharges'
;
const
dimensions
=
{};
return
this
.
getDimensionValues
(
region
,
namespace
,
metricName
,
'ServiceName'
,
dimensions
).
then
(
()
=>
{
return
{
status
:
'success'
,
message
:
'Data source is working'
};
},
err
=>
{
return
{
status
:
'error'
,
message
:
err
.
message
};
}
);
return
this
.
getDimensionValues
(
region
,
namespace
,
metricName
,
'ServiceName'
,
dimensions
).
then
(()
=>
{
return
{
status
:
'success'
,
message
:
'Data source is working'
};
});
}
awsRequest
(
url
,
data
)
{
...
...
public/app/routes/ReactContainer.tsx
View file @
e0feb726
...
...
@@ -3,7 +3,7 @@ import ReactDOM from 'react-dom';
import
{
Provider
}
from
'react-redux'
;
import
coreModule
from
'app/core/core_module'
;
import
{
store
}
from
'app/store/
configureS
tore'
;
import
{
store
}
from
'app/store/
s
tore'
;
import
{
BackendSrv
}
from
'app/core/services/backend_srv'
;
import
{
DatasourceSrv
}
from
'app/features/plugins/datasource_srv'
;
import
{
ContextSrv
}
from
'app/core/services/context_srv'
;
...
...
public/app/routes/routes.ts
View file @
e0feb726
...
...
@@ -14,6 +14,7 @@ import DataSourcesListPage from 'app/features/datasources/DataSourcesListPage';
import
NewDataSourcePage
from
'../features/datasources/NewDataSourcePage'
;
import
UsersListPage
from
'app/features/users/UsersListPage'
;
import
DataSourceDashboards
from
'app/features/datasources/DataSourceDashboards'
;
import
DataSourceSettings
from
'../features/datasources/settings/DataSourceSettings'
;
import
OrgDetailsPage
from
'../features/org/OrgDetailsPage'
;
/** @ngInject */
...
...
@@ -74,10 +75,11 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
component
:
()
=>
DataSourcesListPage
,
},
})
.
when
(
'/datasources/edit/:id'
,
{
templateUrl
:
'public/app/features/plugins/partials/ds_edit.html'
,
controller
:
'DataSourceEditCtrl'
,
controllerAs
:
'ctrl'
,
.
when
(
'/datasources/edit/:id/'
,
{
template
:
'<react-container />'
,
resolve
:
{
component
:
()
=>
DataSourceSettings
,
},
})
.
when
(
'/datasources/edit/:id/dashboards'
,
{
template
:
'<react-container />'
,
...
...
public/app/store/configureStore.ts
View file @
e0feb726
...
...
@@ -11,6 +11,7 @@ import pluginReducers from 'app/features/plugins/state/reducers';
import
dataSourcesReducers
from
'app/features/datasources/state/reducers'
;
import
usersReducers
from
'app/features/users/state/reducers'
;
import
organizationReducers
from
'app/features/org/state/reducers'
;
import
{
setStore
}
from
'./store'
;
const
rootReducers
=
{
...
sharedReducers
,
...
...
@@ -25,8 +26,6 @@ const rootReducers = {
...
organizationReducers
,
};
export
let
store
;
export
function
addRootReducer
(
reducers
)
{
Object
.
assign
(
rootReducers
,
...
reducers
);
}
...
...
@@ -38,8 +37,8 @@ export function configureStore() {
if
(
process
.
env
.
NODE_ENV
!==
'production'
)
{
// DEV builds we had the logger middleware
s
tore
=
createStore
(
rootReducer
,
{},
composeEnhancers
(
applyMiddleware
(
thunk
,
createLogger
(
))));
s
etStore
(
createStore
(
rootReducer
,
{},
composeEnhancers
(
applyMiddleware
(
thunk
,
createLogger
()
))));
}
else
{
s
tore
=
createStore
(
rootReducer
,
{},
composeEnhancers
(
applyMiddleware
(
thunk
)));
s
etStore
(
createStore
(
rootReducer
,
{},
composeEnhancers
(
applyMiddleware
(
thunk
)
)));
}
}
public/app/store/store.ts
0 → 100644
View file @
e0feb726
export
let
store
;
export
function
setStore
(
newStore
)
{
store
=
newStore
;
}
public/app/types/datasources.ts
View file @
e0feb726
...
...
@@ -13,9 +13,12 @@ export interface DataSource {
user
:
string
;
database
:
string
;
basicAuth
:
boolean
;
basicAuthPassword
:
string
;
basicAuthUser
:
string
;
isDefault
:
boolean
;
jsonData
:
{
authType
:
string
;
defaultRegion
:
string
};
readOnly
:
boolean
;
withCredentials
:
boolean
;
meta
?:
PluginMeta
;
pluginExports
?:
PluginExports
;
init
?:
()
=>
void
;
...
...
public/app/types/plugins.ts
View file @
e0feb726
...
...
@@ -73,6 +73,7 @@ export interface Plugin {
pinned
:
boolean
;
state
:
string
;
type
:
string
;
module
:
any
;
}
export
interface
PluginDashboard
{
...
...
public/app/types/series.ts
View file @
e0feb726
...
...
@@ -88,4 +88,5 @@ export interface DataQueryOptions {
export
interface
DataSourceApi
{
query
(
options
:
DataQueryOptions
):
Promise
<
DataQueryResponse
>
;
testDatasource
():
Promise
<
any
>
;
}
scripts/webpack/webpack.hot.js
View file @
e0feb726
...
...
@@ -4,22 +4,19 @@ const merge = require('webpack-merge');
const
common
=
require
(
'./webpack.common.js'
);
const
path
=
require
(
'path'
);
const
webpack
=
require
(
'webpack'
);
const
HtmlWebpackPlugin
=
require
(
"html-webpack-plugin"
);
const
HtmlWebpackPlugin
=
require
(
'html-webpack-plugin'
);
const
HtmlWebpackHarddiskPlugin
=
require
(
'html-webpack-harddisk-plugin'
);
const
CleanWebpackPlugin
=
require
(
'clean-webpack-plugin'
);
module
.
exports
=
merge
(
common
,
{
entry
:
{
app
:
[
'webpack-dev-server/client?http://localhost:3333'
,
'./public/app/dev.ts'
,
],
app
:
[
'webpack-dev-server/client?http://localhost:3333'
,
'./public/app/dev.ts'
],
},
output
:
{
path
:
path
.
resolve
(
__dirname
,
'../../public/build'
),
filename
:
'[name].[hash].js'
,
publicPath
:
"/public/build/"
,
publicPath
:
'/public/build/'
,
pathinfo
:
false
,
},
...
...
@@ -34,8 +31,8 @@ module.exports = merge(common, {
hot
:
true
,
port
:
3333
,
proxy
:
{
'!/public/build'
:
'http://localhost:3000'
}
'!/public/build'
:
'http://localhost:3000'
,
}
,
},
optimization
:
{
...
...
@@ -49,38 +46,37 @@ module.exports = merge(common, {
{
test
:
/
\.
tsx
?
$/
,
exclude
:
/node_modules/
,
use
:
[{
loader
:
'babel-loader'
,
options
:
{
cacheDirectory
:
true
,
babelrc
:
false
,
plugins
:
[
'syntax-dynamic-import'
,
'react-hot-loader/babel'
]
}
},
{
loader
:
'ts-loader'
,
options
:
{
transpileOnly
:
true
,
experimentalWatchApi
:
true
use
:
[
{
loader
:
'babel-loader'
,
options
:
{
cacheDirectory
:
true
,
babelrc
:
false
,
plugins
:
[
'syntax-dynamic-import'
,
'react-hot-loader/babel'
],
},
},
}],
{
loader
:
'ts-loader'
,
options
:
{
transpileOnly
:
true
,
experimentalWatchApi
:
true
,
},
},
],
},
{
test
:
/
\.
scss$/
,
use
:
[
"style-loader"
,
// creates style nodes from JS strings
"css-loader"
,
// translates CSS into CommonJS
"sass-loader"
// compiles Sass to CSS
]
'style-loader'
,
// creates style nodes from JS strings
'css-loader'
,
// translates CSS into CommonJS
'sass-loader'
,
// compiles Sass to CSS
]
,
},
{
test
:
/
\.(
png|jpg|gif|ttf|eot|svg|woff
(
2
)?)(\?[
a-z0-9=&.
]
+
)?
$/
,
loader
:
'file-loader'
loader
:
'file-loader'
,
},
]
]
,
},
plugins
:
[
...
...
@@ -89,16 +85,16 @@ module.exports = merge(common, {
filename
:
path
.
resolve
(
__dirname
,
'../../public/views/index.html'
),
template
:
path
.
resolve
(
__dirname
,
'../../public/views/index-template.html'
),
inject
:
'body'
,
alwaysWriteToDisk
:
true
alwaysWriteToDisk
:
true
,
}),
new
HtmlWebpackHarddiskPlugin
(),
new
webpack
.
NamedModulesPlugin
(),
new
webpack
.
HotModuleReplacementPlugin
(),
new
webpack
.
DefinePlugin
({
'GRAFANA_THEME'
:
JSON
.
stringify
(
process
.
env
.
GRAFANA_THEME
||
'dark'
),
GRAFANA_THEME
:
JSON
.
stringify
(
process
.
env
.
GRAFANA_THEME
||
'dark'
),
'process.env'
:
{
'NODE_ENV'
:
JSON
.
stringify
(
'development'
)
}
NODE_ENV
:
JSON
.
stringify
(
'development'
),
}
,
}),
]
]
,
});
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