Merge remote-tracking branch 'grafana/master' into influx-db-query2
This commit is contained in:
@@ -25,6 +25,7 @@ public/css/*.min.css
|
|||||||
*.swp
|
*.swp
|
||||||
.idea/
|
.idea/
|
||||||
*.iml
|
*.iml
|
||||||
|
*.tmp
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
/data/*
|
/data/*
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
* **Units**: New number format: Scientific notation [#7781](https://github.com/grafana/grafana/issues/7781) thx [@cadnce](https://github.com/cadnce)
|
* **Units**: New number format: Scientific notation [#7781](https://github.com/grafana/grafana/issues/7781) thx [@cadnce](https://github.com/cadnce)
|
||||||
* **Oauth**: Add common type for oauth authorization errors [#6428](https://github.com/grafana/grafana/issues/6428) thx [@amenzhinsky](https://github.com/amenzhinsky)
|
* **Oauth**: Add common type for oauth authorization errors [#6428](https://github.com/grafana/grafana/issues/6428) thx [@amenzhinsky](https://github.com/amenzhinsky)
|
||||||
* **Templating**: Data source variable now supports multi value and panel repeats [#7030](https://github.com/grafana/grafana/issues/7030) thx [@mtanda](https://github.com/mtanda)
|
* **Templating**: Data source variable now supports multi value and panel repeats [#7030](https://github.com/grafana/grafana/issues/7030) thx [@mtanda](https://github.com/mtanda)
|
||||||
|
* **Telegram**: Telegram alert is not sending metric and legend. [#8110](https://github.com/grafana/grafana/issues/8110), thx [@bashgeek](https://github.com/bashgeek)
|
||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
* **Table Panel**: Fixed annotation display in table panel, [#8023](https://github.com/grafana/grafana/issues/8023)
|
* **Table Panel**: Fixed annotation display in table panel, [#8023](https://github.com/grafana/grafana/issues/8023)
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
# Roadmap (2017-04-23)
|
||||||
|
|
||||||
|
This roadmap is a tentative plan for the core development team. Things change constantly as PRs come in and priorities change.
|
||||||
|
But it will give you an idea of our current vision and plan.
|
||||||
|
|
||||||
|
### Short term (1-4 months)
|
||||||
|
|
||||||
|
- New Heatmap Panel (Implemented and available in master)
|
||||||
|
- Support for MySQL & Postgres as data sources (Work started and a alpha version for MySQL is available in master)
|
||||||
|
- User Groups & Dashboard folders with ACLs (work started, not yet completed, https://github.com/grafana/grafana/issues/1611#issuecomment-287742633)
|
||||||
|
- Improve new user UX
|
||||||
|
- Improve docs
|
||||||
|
- Support for alerting for Elasticsearch (can be tested in [branch](https://github.com/grafana/grafana/tree/alerting-elasticsearch) but needs more work)
|
||||||
|
- Graph annotations (create from grafana, region annotations, better annotation viz)
|
||||||
|
- Improve alerting (clustering, silence rules)
|
||||||
|
|
||||||
|
### Long term
|
||||||
|
|
||||||
|
- Improved dashboard panel layout engine (to make it easier and enable more flexible layouts)
|
||||||
|
- Backend plugins to support more Auth options, Alerting data sources & notifications
|
||||||
|
- Universial time series transformations for any data source (meta queries)
|
||||||
|
- Reporting
|
||||||
|
- Web socket & live data streams
|
||||||
|
- Migrate to Angular2
|
||||||
|
|
||||||
|
|
||||||
|
### Outside contributions
|
||||||
|
We know this is being worked on right now by contributors (and we hope to merge it when it's ready).
|
||||||
|
|
||||||
|
- Dashboard revisions (be able to revert dashboard changes)
|
||||||
|
- Clustering for alert engine (load distribution)
|
||||||
@@ -10,3 +10,5 @@ mysql:
|
|||||||
volumes:
|
volumes:
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
- /etc/timezone:/etc/timezone:ro
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
## MySQL with Open Data Set from NYC Open Data (https://data.cityofnewyork.us)
|
||||||
|
|
||||||
|
FROM mysql:latest
|
||||||
|
|
||||||
|
ENV MYSQL_DATABASE="testdata" \
|
||||||
|
MYSQL_ROOT_PASSWORD="rootpass" \
|
||||||
|
MYSQL_USER="grafana" \
|
||||||
|
MYSQL_PASSWORD="password"
|
||||||
|
|
||||||
|
# Install requirement (wget)
|
||||||
|
RUN apt-get update && apt-get install -y wget && apt-get install unzip
|
||||||
|
|
||||||
|
# Fetch NYC Data Set
|
||||||
|
RUN wget https://data.cityofnewyork.us/download/57g5-etyj/application%2Fzip -O /tmp/data.zip && \
|
||||||
|
unzip -j /tmp/data.zip 311_Service_Requests_from_2015.csv -d /var/lib/mysql-files && \
|
||||||
|
rm /tmp/data.zip
|
||||||
|
|
||||||
|
ADD import_csv.sql /docker-entrypoint-initdb.d/
|
||||||
|
|
||||||
|
EXPOSE 3306
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
mysql_opendata:
|
||||||
|
build: blocks/mysql_opendata
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: rootpass
|
||||||
|
MYSQL_DATABASE: testdata
|
||||||
|
MYSQL_USER: grafana
|
||||||
|
MYSQL_PASSWORD: password
|
||||||
|
ports:
|
||||||
|
- "3307:3306"
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
use testdata;
|
||||||
|
DROP TABLE IF EXISTS `nyc_open_data`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `nyc_open_data` (
|
||||||
|
UniqueKey bigint(255),
|
||||||
|
`CreatedDate` varchar(255),
|
||||||
|
`ClosedDate` varchar(255),
|
||||||
|
Agency varchar(255),
|
||||||
|
AgencyName varchar(255),
|
||||||
|
ComplaintType varchar(255),
|
||||||
|
Descriptor varchar(255),
|
||||||
|
LocationType varchar(255),
|
||||||
|
IncidentZip varchar(255),
|
||||||
|
IncidentAddress varchar(255),
|
||||||
|
StreetName varchar(255),
|
||||||
|
CrossStreet1 varchar(255),
|
||||||
|
CrossStreet2 varchar(255),
|
||||||
|
IntersectionStreet1 varchar(255),
|
||||||
|
IntersectionStreet2 varchar(255),
|
||||||
|
AddressType varchar(255),
|
||||||
|
City varchar(255),
|
||||||
|
Landmark varchar(255),
|
||||||
|
FacilityType varchar(255),
|
||||||
|
Status varchar(255),
|
||||||
|
`DueDate` varchar(255),
|
||||||
|
ResolutionDescription varchar(2048),
|
||||||
|
`ResolutionActionUpdatedDate` varchar(255),
|
||||||
|
CommunityBoard varchar(255),
|
||||||
|
Borough varchar(255),
|
||||||
|
XCoordinateStatePlane varchar(255),
|
||||||
|
YCoordinateStatePlane varchar(255),
|
||||||
|
ParkFacilityName varchar(255),
|
||||||
|
ParkBorough varchar(255),
|
||||||
|
SchoolName varchar(255),
|
||||||
|
SchoolNumber varchar(255),
|
||||||
|
SchoolRegion varchar(255),
|
||||||
|
SchoolCode varchar(255),
|
||||||
|
SchoolPhoneNumber varchar(255),
|
||||||
|
SchoolAddress varchar(255),
|
||||||
|
SchoolCity varchar(255),
|
||||||
|
SchoolState varchar(255),
|
||||||
|
SchoolZip varchar(255),
|
||||||
|
SchoolNotFound varchar(255),
|
||||||
|
SchoolOrCitywideComplaint varchar(255),
|
||||||
|
VehicleType varchar(255),
|
||||||
|
TaxiCompanyBorough varchar(255),
|
||||||
|
TaxiPickUpLocation varchar(255),
|
||||||
|
BridgeHighwayName varchar(255),
|
||||||
|
BridgeHighwayDirection varchar(255),
|
||||||
|
RoadRamp varchar(255),
|
||||||
|
BridgeHighwaySegment varchar(255),
|
||||||
|
GarageLotName varchar(255),
|
||||||
|
FerryDirection varchar(255),
|
||||||
|
FerryTerminalName varchar(255),
|
||||||
|
Latitude varchar(255),
|
||||||
|
Longitude varchar(255),
|
||||||
|
Location varchar(255)
|
||||||
|
);
|
||||||
|
LOAD DATA INFILE '/var/lib/mysql-files/311_Service_Requests_from_2015.csv' INTO TABLE nyc_open_data FIELDS OPTIONALLY ENCLOSED BY '"' TERMINATED BY ',' IGNORE 1 LINES;
|
||||||
|
UPDATE nyc_open_data SET CreatedDate = STR_TO_DATE(CreatedDate, '%m/%d/%Y %r') WHERE CreatedDate <> '';
|
||||||
|
UPDATE nyc_open_data SET ClosedDate = STR_TO_DATE(ClosedDate, '%m/%d/%Y %r') WHERE ClosedDate <> '';
|
||||||
|
UPDATE nyc_open_data SET DueDate = STR_TO_DATE(DueDate, '%m/%d/%Y %r') WHERE DueDate <> '';
|
||||||
|
UPDATE nyc_open_data SET ResolutionActionUpdatedDate = STR_TO_DATE(ResolutionActionUpdatedDate, '%m/%d/%Y %r') WHERE ResolutionActionUpdatedDate <> '';
|
||||||
|
|
||||||
|
UPDATE nyc_open_data SET CreatedDate=null WHERE CreatedDate = '';
|
||||||
|
UPDATE nyc_open_data SET ClosedDate=null WHERE ClosedDate = '';
|
||||||
|
UPDATE nyc_open_data SET DueDate=null WHERE DueDate = '';
|
||||||
|
UPDATE nyc_open_data SET ResolutionActionUpdatedDate=null WHERE ResolutionActionUpdatedDate = '';
|
||||||
|
|
||||||
|
ALTER TABLE nyc_open_data modify CreatedDate datetime NULL;
|
||||||
|
ALTER TABLE nyc_open_data modify ClosedDate datetime NULL;
|
||||||
|
ALTER TABLE nyc_open_data modify DueDate datetime NULL;
|
||||||
|
ALTER TABLE nyc_open_data modify ResolutionActionUpdatedDate datetime NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `nyc_open_data` ADD INDEX `IX_ComplaintType` (`ComplaintType`);
|
||||||
|
ALTER TABLE `nyc_open_data` ADD INDEX `IX_CreatedDate` (`CreatedDate`);
|
||||||
|
ALTER TABLE `nyc_open_data` ADD INDEX `IX_LocationType` (`LocationType`);
|
||||||
|
ALTER TABLE `nyc_open_data` ADD INDEX `IX_AgencyName` (`AgencyName`);
|
||||||
|
ALTER TABLE `nyc_open_data` ADD INDEX `IX_City` (`City`);
|
||||||
|
|
||||||
|
SYSTEM rm /var/lib/mysql-files/311_Service_Requests_from_2015.csv
|
||||||
@@ -27,6 +27,24 @@ To show all admin commands:
|
|||||||
|
|
||||||
### Reset admin password
|
### Reset admin password
|
||||||
|
|
||||||
You can reset the password for the admin user using the CLI.
|
You can reset the password for the admin user using the CLI. The use case for this command is when you have lost the admin password.
|
||||||
|
|
||||||
`grafana-cli admin reset-admin-password ...`
|
`grafana-cli admin reset-admin-password ...`
|
||||||
|
|
||||||
|
If running the command returns this error:
|
||||||
|
|
||||||
|
> Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath
|
||||||
|
|
||||||
|
then there are two flags that can be used to set homepath and the config file path.
|
||||||
|
|
||||||
|
`grafana-cli admin reset-admin-password --homepath "/usr/share/grafana" newpass`
|
||||||
|
|
||||||
|
If you have not lost the admin password then it is better to set in the Grafana UI. If you need to set the password in a script then the [Grafana API](http://docs.grafana.org/http_api/user/#change-password) can be used. Here is an example with curl using basic auth:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -X PUT -H "Content-Type: application/json" -d '{
|
||||||
|
"oldPassword": "admin",
|
||||||
|
"newPassword": "newpass",
|
||||||
|
"confirmNew": "newpass"
|
||||||
|
}' http://admin:admin@<your_grafana_host>:3000/api/user/password
|
||||||
|
```
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ This API can also be used to create, update and delete alert notifications.
|
|||||||
|
|
||||||
**Example Request**:
|
**Example Request**:
|
||||||
|
|
||||||
DELETE /api/alerts-notifications/1 HTTP/1.1
|
DELETE /api/alert-notifications/1 HTTP/1.1
|
||||||
Accept: application/json
|
Accept: application/json
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
|||||||
@@ -41,3 +41,80 @@ You use the token in all requests in the `Authorization` header, like this:
|
|||||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
|
||||||
The `Authorization` header value should be `Bearer <your api key>`.
|
The `Authorization` header value should be `Bearer <your api key>`.
|
||||||
|
|
||||||
|
# Auth HTTP resources / actions
|
||||||
|
|
||||||
|
## Api Keys
|
||||||
|
|
||||||
|
`GET /api/auth/keys`
|
||||||
|
|
||||||
|
**Example Request**:
|
||||||
|
|
||||||
|
GET /api/auth/keys HTTP/1.1
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
|
||||||
|
**Example Response**:
|
||||||
|
|
||||||
|
HTTP/1.1 200
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "API",
|
||||||
|
"role": "Admin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "TestAdmin",
|
||||||
|
"role": "Admin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
## Create API Key
|
||||||
|
|
||||||
|
`POST /api/auth/keys`
|
||||||
|
|
||||||
|
**Example Request**:
|
||||||
|
|
||||||
|
POST /api/auth/keys HTTP/1.1
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "mykey",
|
||||||
|
"role": "Admin"
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON Body schema:
|
||||||
|
|
||||||
|
- **name** – The key name
|
||||||
|
- **role** – Sets the access level/Grafana Role for the key. Can be one of the following values: `Viewer`, `Editor`, `Read Only Editor` or `Admin`.
|
||||||
|
|
||||||
|
**Example Response**:
|
||||||
|
|
||||||
|
HTTP/1.1 200
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"name":"mykey","key":"eyJrIjoiWHZiSWd3NzdCYUZnNUtibE9obUpESmE3bzJYNDRIc0UiLCJuIjoibXlrZXkiLCJpZCI6MX1="}
|
||||||
|
|
||||||
|
## Delete API Key
|
||||||
|
|
||||||
|
`DELETE /api/auth/keys/:id`
|
||||||
|
|
||||||
|
**Example Request**:
|
||||||
|
|
||||||
|
DELETE /api/auth/keys/3 HTTP/1.1
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
|
||||||
|
**Example Response**:
|
||||||
|
|
||||||
|
HTTP/1.1 200
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"message":"API key deleted"}
|
||||||
|
|||||||
+2
-2
@@ -76,8 +76,8 @@
|
|||||||
"systemjs-builder": "^0.15.34",
|
"systemjs-builder": "^0.15.34",
|
||||||
"tether": "^1.4.0",
|
"tether": "^1.4.0",
|
||||||
"tether-drop": "https://github.com/torkelo/drop",
|
"tether-drop": "https://github.com/torkelo/drop",
|
||||||
"tslint": "^4.5.1",
|
"tslint": "^5.1.0",
|
||||||
"typescript": "^2.1.4",
|
"typescript": "^2.2.2",
|
||||||
"virtual-scroll": "^1.1.1"
|
"virtual-scroll": "^1.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -50,13 +50,16 @@ func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response {
|
|||||||
return ApiError(500, "Metric request error", err)
|
return ApiError(500, "Metric request error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statusCode := 200
|
||||||
for _, res := range resp.Results {
|
for _, res := range resp.Results {
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
res.ErrorString = res.Error.Error()
|
res.ErrorString = res.Error.Error()
|
||||||
|
resp.Message = res.ErrorString
|
||||||
|
statusCode = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Json(200, &resp)
|
return Json(statusCode, &resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /api/tsdb/testdata/scenarios
|
// GET /api/tsdb/testdata/scenarios
|
||||||
|
|||||||
@@ -11,22 +11,18 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
var configFile = flag.String("config", "", "path to config file")
|
|
||||||
var homePath = flag.String("homepath", "", "path to grafana install/home path, defaults to working directory")
|
|
||||||
|
|
||||||
func runDbCommand(command func(commandLine CommandLine) error) func(context *cli.Context) {
|
func runDbCommand(command func(commandLine CommandLine) error) func(context *cli.Context) {
|
||||||
return func(context *cli.Context) {
|
return func(context *cli.Context) {
|
||||||
|
cmd := &contextCommandLine{context}
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
setting.NewConfigContext(&setting.CommandLineArgs{
|
setting.NewConfigContext(&setting.CommandLineArgs{
|
||||||
Config: *configFile,
|
Config: cmd.String("config"),
|
||||||
HomePath: *homePath,
|
HomePath: cmd.String("homepath"),
|
||||||
Args: flag.Args(),
|
Args: flag.Args(),
|
||||||
})
|
})
|
||||||
|
|
||||||
sqlstore.NewEngine()
|
sqlstore.NewEngine()
|
||||||
|
|
||||||
cmd := &contextCommandLine{context}
|
|
||||||
if err := command(cmd); err != nil {
|
if err := command(cmd); err != nil {
|
||||||
logger.Errorf("\n%s: ", color.RedString("Error"))
|
logger.Errorf("\n%s: ", color.RedString("Error"))
|
||||||
logger.Errorf("%s\n\n", err)
|
logger.Errorf("%s\n\n", err)
|
||||||
@@ -95,6 +91,16 @@ var adminCommands = []cli.Command{
|
|||||||
Name: "reset-admin-password",
|
Name: "reset-admin-password",
|
||||||
Usage: "reset-admin-password <new password>",
|
Usage: "reset-admin-password <new password>",
|
||||||
Action: runDbCommand(resetPasswordCommand),
|
Action: runDbCommand(resetPasswordCommand),
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "homepath",
|
||||||
|
Usage: "path to grafana install/home path, defaults to working directory",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Usage: "path to config file",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error {
|
|||||||
bodyJSON.Set("chat_id", this.ChatID)
|
bodyJSON.Set("chat_id", this.ChatID)
|
||||||
bodyJSON.Set("parse_mode", "html")
|
bodyJSON.Set("parse_mode", "html")
|
||||||
|
|
||||||
message := fmt.Sprintf("%s\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message)
|
message := fmt.Sprintf("<b>%s</b>\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message)
|
||||||
|
|
||||||
ruleUrl, err := evalContext.GetRuleUrl()
|
ruleUrl, err := evalContext.GetRuleUrl()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -96,6 +96,19 @@ func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error {
|
|||||||
if evalContext.ImagePublicUrl != "" {
|
if evalContext.ImagePublicUrl != "" {
|
||||||
message = message + fmt.Sprintf("Image: %s\n", evalContext.ImagePublicUrl)
|
message = message + fmt.Sprintf("Image: %s\n", evalContext.ImagePublicUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metrics := ""
|
||||||
|
fieldLimitCount := 4
|
||||||
|
for index, evt := range evalContext.EvalMatches {
|
||||||
|
metrics += fmt.Sprintf("\n%s: %s", evt.Metric, evt.Value)
|
||||||
|
if index > fieldLimitCount {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if metrics != "" {
|
||||||
|
message = message + fmt.Sprintf("\n<i>Metrics:</i>%s", metrics)
|
||||||
|
}
|
||||||
|
|
||||||
bodyJSON.Set("text", message)
|
bodyJSON.Set("text", message)
|
||||||
|
|
||||||
url := fmt.Sprintf(telegeramApiUrl, this.BotToken, "sendMessage")
|
url := fmt.Sprintf(telegeramApiUrl, this.BotToken, "sendMessage")
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ func AddMigrations(mg *Migrator) {
|
|||||||
addPreferencesMigrations(mg)
|
addPreferencesMigrations(mg)
|
||||||
addAlertMigrations(mg)
|
addAlertMigrations(mg)
|
||||||
addAnnotationMig(mg)
|
addAnnotationMig(mg)
|
||||||
addStatsMigrations(mg)
|
|
||||||
addTestDataMigrations(mg)
|
addTestDataMigrations(mg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ func init() {
|
|||||||
|
|
||||||
func sqlRandomWalk(m1 string, m2 string, intWalker int64, floatWalker float64, sess *session) error {
|
func sqlRandomWalk(m1 string, m2 string, intWalker int64, floatWalker float64, sess *session) error {
|
||||||
|
|
||||||
timeWalker := time.Now().UTC().Add(time.Hour * -1)
|
timeWalker := time.Now().UTC().Add(time.Hour * -200)
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
step := time.Minute
|
step := time.Minute
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ func sqlRandomWalk(m1 string, m2 string, intWalker int64, floatWalker float64, s
|
|||||||
timeWalker = timeWalker.Add(step)
|
timeWalker = timeWalker.Add(step)
|
||||||
|
|
||||||
row.Id = 0
|
row.Id = 0
|
||||||
row.ValueBigInt += rand.Int63n(100) - 100
|
row.ValueBigInt += rand.Int63n(200) - 100
|
||||||
row.ValueDouble += rand.Float64() - 0.5
|
row.ValueDouble += rand.Float64() - 0.5
|
||||||
row.ValueFloat += rand.Float32() - 0.5
|
row.ValueFloat += rand.Float32() - 0.5
|
||||||
row.TimeEpoch = timeWalker.Unix()
|
row.TimeEpoch = timeWalker.Unix()
|
||||||
@@ -61,11 +61,6 @@ func InsertSqlTestData(cmd *m.InsertSqlTestDataCommand) error {
|
|||||||
sqlRandomWalk("server2", "frontend", 100, 1.123, sess)
|
sqlRandomWalk("server2", "frontend", 100, 1.123, sess)
|
||||||
sqlRandomWalk("server3", "frontend", 100, 1.123, sess)
|
sqlRandomWalk("server3", "frontend", 100, 1.123, sess)
|
||||||
|
|
||||||
sqlRandomWalk("server1", "backend", 100, 1.123, sess)
|
|
||||||
sqlRandomWalk("server2", "backend", 100, 1.123, sess)
|
|
||||||
sqlRandomWalk("server3", "backend", 100, 1.123, sess)
|
|
||||||
sqlRandomWalk("db-server1", "backend", 100, 1.123, sess)
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-5
@@ -27,6 +27,7 @@ type Request struct {
|
|||||||
type Response struct {
|
type Response struct {
|
||||||
BatchTimings []*BatchTiming `json:"timings"`
|
BatchTimings []*BatchTiming `json:"timings"`
|
||||||
Results map[string]*QueryResult `json:"results"`
|
Results map[string]*QueryResult `json:"results"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BatchTiming struct {
|
type BatchTiming struct {
|
||||||
@@ -45,18 +46,30 @@ func (br *BatchResult) WithError(err error) *BatchResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QueryResult struct {
|
type QueryResult struct {
|
||||||
Error error `json:"-"`
|
Error error `json:"-"`
|
||||||
ErrorString string `json:"error"`
|
ErrorString string `json:"error,omitempty"`
|
||||||
RefId string `json:"refId"`
|
RefId string `json:"refId"`
|
||||||
Series TimeSeriesSlice `json:"series"`
|
Meta *simplejson.Json `json:"meta,omitempty"`
|
||||||
|
Series TimeSeriesSlice `json:"series"`
|
||||||
|
Tables []*Table `json:"tables"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TimeSeries struct {
|
type TimeSeries struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Points TimeSeriesPoints `json:"points"`
|
Points TimeSeriesPoints `json:"points"`
|
||||||
Tags map[string]string `json:"tags"`
|
Tags map[string]string `json:"tags,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Table struct {
|
||||||
|
Columns []TableColumn `json:"columns"`
|
||||||
|
Rows []RowValues `json:"rows"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TableColumn struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RowValues []interface{}
|
||||||
type TimePoint [2]null.Float
|
type TimePoint [2]null.Float
|
||||||
type TimeSeriesPoints []TimePoint
|
type TimeSeriesPoints []TimePoint
|
||||||
type TimeSeriesSlice []*TimeSeries
|
type TimeSeriesSlice []*TimeSeries
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
//const rsString = `(?:"([^"]*)")`;
|
||||||
|
const rsIdentifier = `([_a-zA-Z0-9]+)`
|
||||||
|
const sExpr = `\$` + rsIdentifier + `\(([^\)]*)\)`
|
||||||
|
|
||||||
|
type SqlMacroEngine interface {
|
||||||
|
Interpolate(sql string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type MySqlMacroEngine struct {
|
||||||
|
TimeRange *tsdb.TimeRange
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMysqlMacroEngine(timeRange *tsdb.TimeRange) SqlMacroEngine {
|
||||||
|
return &MySqlMacroEngine{
|
||||||
|
TimeRange: timeRange,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MySqlMacroEngine) Interpolate(sql string) (string, error) {
|
||||||
|
rExp, _ := regexp.Compile(sExpr)
|
||||||
|
var macroError error
|
||||||
|
|
||||||
|
sql = ReplaceAllStringSubmatchFunc(rExp, sql, func(groups []string) string {
|
||||||
|
res, err := m.EvaluateMacro(groups[1], groups[2:])
|
||||||
|
if err != nil && macroError == nil {
|
||||||
|
macroError = err
|
||||||
|
return "macro_error()"
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
|
||||||
|
if macroError != nil {
|
||||||
|
return "", macroError
|
||||||
|
}
|
||||||
|
|
||||||
|
return sql, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReplaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string {
|
||||||
|
result := ""
|
||||||
|
lastIndex := 0
|
||||||
|
|
||||||
|
for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) {
|
||||||
|
groups := []string{}
|
||||||
|
for i := 0; i < len(v); i += 2 {
|
||||||
|
groups = append(groups, str[v[i]:v[i+1]])
|
||||||
|
}
|
||||||
|
|
||||||
|
result += str[lastIndex:v[0]] + repl(groups)
|
||||||
|
lastIndex = v[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return result + str[lastIndex:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MySqlMacroEngine) EvaluateMacro(name string, args []string) (string, error) {
|
||||||
|
switch name {
|
||||||
|
case "__time":
|
||||||
|
if len(args) == 0 {
|
||||||
|
return "", fmt.Errorf("missing time column argument for macro %v", name)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("UNIX_TIMESTAMP(%s) as time_sec", args[0]), nil
|
||||||
|
case "__timeFilter":
|
||||||
|
if len(args) == 0 {
|
||||||
|
return "", fmt.Errorf("missing time column argument for macro %v", name)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s > FROM_UNIXTIME(%d) AND %s < FROM_UNIXTIME(%d)", args[0], uint64(m.TimeRange.GetFromAsMsEpoch()/1000), args[0], uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("Unknown macro %v", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMacroEngine(t *testing.T) {
|
||||||
|
Convey("MacroEngine", t, func() {
|
||||||
|
|
||||||
|
Convey("interpolate __time function", func() {
|
||||||
|
engine := &MySqlMacroEngine{}
|
||||||
|
|
||||||
|
sql, err := engine.Interpolate("select $__time(time_column)")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
So(sql, ShouldEqual, "select UNIX_TIMESTAMP(time_column) as time_sec")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("interpolate __time function wrapped in aggregation", func() {
|
||||||
|
engine := &MySqlMacroEngine{}
|
||||||
|
|
||||||
|
sql, err := engine.Interpolate("select min($__time(time_column))")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
So(sql, ShouldEqual, "select min(UNIX_TIMESTAMP(time_column) as time_sec)")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("interpolate __timeFilter function", func() {
|
||||||
|
engine := &MySqlMacroEngine{
|
||||||
|
TimeRange: &tsdb.TimeRange{From: "5m", To: "now"},
|
||||||
|
}
|
||||||
|
|
||||||
|
sql, err := engine.Interpolate("WHERE $__timeFilter(time_column)")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
So(sql, ShouldEqual, "WHERE time_column > FROM_UNIXTIME(18446744066914186738) AND time_column < FROM_UNIXTIME(18446744066914187038)")
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
+117
-14
@@ -7,9 +7,13 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-sql-driver/mysql"
|
||||||
"github.com/go-xorm/core"
|
"github.com/go-xorm/core"
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"github.com/grafana/grafana/pkg/components/null"
|
"github.com/grafana/grafana/pkg/components/null"
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/tsdb"
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
@@ -81,6 +85,7 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co
|
|||||||
QueryResults: make(map[string]*tsdb.QueryResult),
|
QueryResults: make(map[string]*tsdb.QueryResult),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macroEngine := NewMysqlMacroEngine(context.TimeRange)
|
||||||
session := e.engine.NewSession()
|
session := e.engine.NewSession()
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
db := session.DB()
|
db := session.DB()
|
||||||
@@ -91,48 +96,145 @@ func (e *MysqlExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, co
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: query.RefId}
|
||||||
|
result.QueryResults[query.RefId] = queryResult
|
||||||
|
|
||||||
|
rawSql, err := macroEngine.Interpolate(rawSql)
|
||||||
|
if err != nil {
|
||||||
|
queryResult.Error = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult.Meta.Set("sql", rawSql)
|
||||||
|
|
||||||
rows, err := db.Query(rawSql)
|
rows, err := db.Query(rawSql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.QueryResults[query.RefId] = &tsdb.QueryResult{Error: err}
|
queryResult.Error = err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
result.QueryResults[query.RefId] = e.TransformToTimeSeries(query, rows)
|
format := query.Model.Get("format").MustString("time_series")
|
||||||
|
|
||||||
|
switch format {
|
||||||
|
case "time_series":
|
||||||
|
err := e.TransformToTimeSeries(query, rows, queryResult)
|
||||||
|
if err != nil {
|
||||||
|
queryResult.Error = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case "table":
|
||||||
|
err := e.TransformToTable(query, rows, queryResult)
|
||||||
|
if err != nil {
|
||||||
|
queryResult.Error = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows) *tsdb.QueryResult {
|
func (e MysqlExecutor) TransformToTable(query *tsdb.Query, rows *core.Rows, result *tsdb.QueryResult) error {
|
||||||
result := &tsdb.QueryResult{RefId: query.RefId}
|
columnNames, err := rows.Columns()
|
||||||
|
columnCount := len(columnNames)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
table := &tsdb.Table{
|
||||||
|
Columns: make([]tsdb.TableColumn, columnCount),
|
||||||
|
Rows: make([]tsdb.RowValues, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, name := range columnNames {
|
||||||
|
table.Columns[i].Text = name
|
||||||
|
}
|
||||||
|
|
||||||
|
columnTypes, err := rows.ColumnTypes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rowLimit := 1000000
|
||||||
|
rowCount := 0
|
||||||
|
|
||||||
|
for ; rows.Next(); rowCount += 1 {
|
||||||
|
if rowCount > rowLimit {
|
||||||
|
return fmt.Errorf("MySQL query row limit exceeded, limit %d", rowLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
values, err := e.getTypedRowData(columnTypes, rows)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Rows = append(table.Rows, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Tables = append(result.Tables, table)
|
||||||
|
result.Meta.Set("rowCount", rowCount)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MysqlExecutor) getTypedRowData(types []*sql.ColumnType, rows *core.Rows) (tsdb.RowValues, error) {
|
||||||
|
values := make([]interface{}, len(types))
|
||||||
|
|
||||||
|
for i, stype := range types {
|
||||||
|
switch stype.DatabaseTypeName() {
|
||||||
|
case mysql.FieldTypeNameVarString:
|
||||||
|
values[i] = new(string)
|
||||||
|
case mysql.FieldTypeNameLongLong:
|
||||||
|
values[i] = new(int64)
|
||||||
|
case mysql.FieldTypeNameDouble:
|
||||||
|
values[i] = new(float64)
|
||||||
|
case mysql.FieldTypeNameDateTime:
|
||||||
|
values[i] = new(time.Time)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Database type %s not supported", stype.DatabaseTypeName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rows.Scan(values...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return values, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows, result *tsdb.QueryResult) error {
|
||||||
pointsBySeries := make(map[string]*tsdb.TimeSeries)
|
pointsBySeries := make(map[string]*tsdb.TimeSeries)
|
||||||
columnNames, err := rows.Columns()
|
columnNames, err := rows.Columns()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.Error = err
|
return err
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rowData := NewStringStringScan(columnNames)
|
rowData := NewStringStringScan(columnNames)
|
||||||
for rows.Next() {
|
rowLimit := 1000000
|
||||||
|
rowCount := 0
|
||||||
|
|
||||||
|
for ; rows.Next(); rowCount += 1 {
|
||||||
|
if rowCount > rowLimit {
|
||||||
|
return fmt.Errorf("MySQL query row limit exceeded, limit %d", rowLimit)
|
||||||
|
}
|
||||||
|
|
||||||
err := rowData.Update(rows.Rows)
|
err := rowData.Update(rows.Rows)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.log.Error("Mysql response parsing", "error", err)
|
e.log.Error("MySQL response parsing", "error", err)
|
||||||
result.Error = err
|
return fmt.Errorf("MySQL response parsing error %v", err)
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if rowData.metric == "" {
|
if rowData.metric == "" {
|
||||||
rowData.metric = "Unknown"
|
rowData.metric = "Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
e.log.Info("Rows", "metric", rowData.metric, "time", rowData.time, "value", rowData.value)
|
//e.log.Debug("Rows", "metric", rowData.metric, "time", rowData.time, "value", rowData.value)
|
||||||
|
|
||||||
if !rowData.time.Valid {
|
if !rowData.time.Valid {
|
||||||
result.Error = fmt.Errorf("Found row with no time value")
|
return fmt.Errorf("Found row with no time value")
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if series, exist := pointsBySeries[rowData.metric]; exist {
|
if series, exist := pointsBySeries[rowData.metric]; exist {
|
||||||
@@ -148,7 +250,8 @@ func (e MysqlExecutor) TransformToTimeSeries(query *tsdb.Query, rows *core.Rows)
|
|||||||
result.Series = append(result.Series, value)
|
result.Series = append(result.Series, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
result.Meta.Set("rowCount", rowCount)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type stringStringScan struct {
|
type stringStringScan struct {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export class SearchCtrl {
|
|||||||
queryHasNoFilters() {
|
queryHasNoFilters() {
|
||||||
var query = this.query;
|
var query = this.query;
|
||||||
return query.query === '' && query.starred === false && query.tag.length === 0;
|
return query.query === '' && query.starred === false && query.tag.length === 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
filterByTag(tag, evt) {
|
filterByTag(tag, evt) {
|
||||||
this.query.tag.push(tag);
|
this.query.tag.push(tag);
|
||||||
@@ -127,7 +127,7 @@ export class SearchCtrl {
|
|||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
removeTag(tag, evt) {
|
removeTag(tag, evt) {
|
||||||
this.query.tag = _.without(this.query.tag, tag);
|
this.query.tag = _.without(this.query.tag, tag);
|
||||||
@@ -135,7 +135,7 @@ export class SearchCtrl {
|
|||||||
this.giveSearchFocus = this.giveSearchFocus + 1;
|
this.giveSearchFocus = this.giveSearchFocus + 1;
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
};
|
}
|
||||||
|
|
||||||
getTags() {
|
getTags() {
|
||||||
return this.backendSrv.get('/api/dashboards/tags').then((results) => {
|
return this.backendSrv.get('/api/dashboards/tags').then((results) => {
|
||||||
@@ -146,19 +146,19 @@ export class SearchCtrl {
|
|||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
showStarred() {
|
showStarred() {
|
||||||
this.query.starred = !this.query.starred;
|
this.query.starred = !this.query.starred;
|
||||||
this.giveSearchFocus = this.giveSearchFocus + 1;
|
this.giveSearchFocus = this.giveSearchFocus + 1;
|
||||||
this.search();
|
this.search();
|
||||||
};
|
}
|
||||||
|
|
||||||
search() {
|
search() {
|
||||||
this.showImport = false;
|
this.showImport = false;
|
||||||
this.selectedIndex = 0;
|
this.selectedIndex = 0;
|
||||||
this.searchDashboards();
|
this.searchDashboards();
|
||||||
};
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,11 @@ export class SideMenuCtrl {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.orgItems.length < this.maxShownOrgs && (this.orgFilter === '' || org.name.indexOf(this.orgFilter) !== -1)){
|
if (this.orgItems.length === this.maxShownOrgs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.orgFilter === '' || (org.name.toLowerCase().indexOf(this.orgFilter.toLowerCase()) !== -1)) {
|
||||||
this.orgItems.push({
|
this.orgItems.push({
|
||||||
text: "Switch to " + org.name,
|
text: "Switch to " + org.name,
|
||||||
icon: "fa fa-fw fa-random",
|
icon: "fa fa-fw fa-random",
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export class SignUpCtrl {
|
|||||||
window.location.href = config.appSubUrl + '/';
|
window.location.href = config.appSubUrl + '/';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
coreModule.controller('SignUpCtrl', SignUpCtrl);
|
coreModule.controller('SignUpCtrl', SignUpCtrl);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $
|
|||||||
|
|
||||||
if (!PanelCtrl || PanelCtrl.registered) {
|
if (!PanelCtrl || PanelCtrl.registered) {
|
||||||
return componentInfo;
|
return componentInfo;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (PanelCtrl.templatePromise) {
|
if (PanelCtrl.templatePromise) {
|
||||||
return PanelCtrl.templatePromise.then(res => {
|
return PanelCtrl.templatePromise.then(res => {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class BackendSrv {
|
|||||||
|
|
||||||
post(url, data) {
|
post(url, data) {
|
||||||
return this.request({ method: 'POST', url: url, data: data });
|
return this.request({ method: 'POST', url: url, data: data });
|
||||||
};
|
}
|
||||||
|
|
||||||
patch(url, data) {
|
patch(url, data) {
|
||||||
return this.request({ method: 'PATCH', url: url, data: data });
|
return this.request({ method: 'PATCH', url: url, data: data });
|
||||||
@@ -98,7 +98,7 @@ export class BackendSrv {
|
|||||||
this.$timeout(this.requestErrorHandler.bind(this, err), 50);
|
this.$timeout(this.requestErrorHandler.bind(this, err), 50);
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
addCanceler(requestId, canceler) {
|
addCanceler(requestId, canceler) {
|
||||||
if (requestId in this.inFlightRequests) {
|
if (requestId in this.inFlightRequests) {
|
||||||
@@ -186,7 +186,7 @@ export class BackendSrv {
|
|||||||
this.inFlightRequests[options.requestId].shift();
|
this.inFlightRequests[options.requestId].shift();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
loginPing() {
|
loginPing() {
|
||||||
return this.request({url: '/api/login/ping', method: 'GET', retry: 1 });
|
return this.request({url: '/api/login/ping', method: 'GET', retry: 1 });
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export default class TimeSeries {
|
|||||||
this.yaxis = override.yaxis;
|
this.yaxis = override.yaxis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
getFlotPairs(fillStyle) {
|
getFlotPairs(fillStyle) {
|
||||||
var result = [];
|
var result = [];
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export function exportSeriesListToCsv(seriesList) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
saveSaveBlob(text, 'grafana_data_export.csv');
|
saveSaveBlob(text, 'grafana_data_export.csv');
|
||||||
};
|
}
|
||||||
|
|
||||||
export function exportSeriesListToCsvColumns(seriesList) {
|
export function exportSeriesListToCsvColumns(seriesList) {
|
||||||
var text = 'sep=;\nTime;';
|
var text = 'sep=;\nTime;';
|
||||||
@@ -47,7 +47,7 @@ export function exportSeriesListToCsvColumns(seriesList) {
|
|||||||
text += '\n';
|
text += '\n';
|
||||||
}
|
}
|
||||||
saveSaveBlob(text, 'grafana_data_export.csv');
|
saveSaveBlob(text, 'grafana_data_export.csv');
|
||||||
};
|
}
|
||||||
|
|
||||||
export function exportTableDataToCsv(table) {
|
export function exportTableDataToCsv(table) {
|
||||||
var text = 'sep=;\n';
|
var text = 'sep=;\n';
|
||||||
@@ -64,9 +64,9 @@ export function exportTableDataToCsv(table) {
|
|||||||
text += '\n';
|
text += '\n';
|
||||||
});
|
});
|
||||||
saveSaveBlob(text, 'grafana_data_export.csv');
|
saveSaveBlob(text, 'grafana_data_export.csv');
|
||||||
};
|
}
|
||||||
|
|
||||||
export function saveSaveBlob(payload, fname) {
|
export function saveSaveBlob(payload, fname) {
|
||||||
var blob = new Blob([payload], { type: "text/csv;charset=utf-8" });
|
var blob = new Blob([payload], { type: "text/csv;charset=utf-8" });
|
||||||
window.saveAs(blob, fname);
|
window.saveAs(blob, fname);
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class AnnotationsEditorCtrl {
|
|||||||
this.reset();
|
this.reset();
|
||||||
this.mode = 'list';
|
this.mode = 'list';
|
||||||
this.$scope.broadcastRefresh();
|
this.$scope.broadcastRefresh();
|
||||||
};
|
}
|
||||||
|
|
||||||
add() {
|
add() {
|
||||||
this.annotations.push(this.currentAnnotation);
|
this.annotations.push(this.currentAnnotation);
|
||||||
@@ -77,7 +77,7 @@ export class AnnotationsEditorCtrl {
|
|||||||
this.mode = 'list';
|
this.mode = 'list';
|
||||||
this.$scope.broadcastRefresh();
|
this.$scope.broadcastRefresh();
|
||||||
this.$scope.dashboard.updateSubmenuVisibility();
|
this.$scope.dashboard.updateSubmenuVisibility();
|
||||||
};
|
}
|
||||||
|
|
||||||
removeAnnotation(annotation) {
|
removeAnnotation(annotation) {
|
||||||
var index = _.indexOf(this.annotations, annotation);
|
var index = _.indexOf(this.annotations, annotation);
|
||||||
|
|||||||
@@ -216,7 +216,6 @@ coreModule.directive('panelDropZone', function($timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (indrag === true) {
|
if (indrag === true) {
|
||||||
var dropZoneSpan = 12 - row.span;
|
|
||||||
if (dropZoneSpan > 1) {
|
if (dropZoneSpan > 1) {
|
||||||
return showPanel(dropZoneSpan, 'Drop Here');
|
return showPanel(dropZoneSpan, 'Drop Here');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class TimeSrv {
|
|||||||
if (_.isString(this.time.to) && this.time.to.indexOf('Z') >= 0) {
|
if (_.isString(this.time.to) && this.time.to.indexOf('Z') >= 0) {
|
||||||
this.time.to = moment(this.time.to).utc();
|
this.time.to = moment(this.time.to).utc();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
private parseUrlParam(value) {
|
private parseUrlParam(value) {
|
||||||
if (value.indexOf('now') !== -1) {
|
if (value.indexOf('now') !== -1) {
|
||||||
@@ -92,7 +92,7 @@ class TimeSrv {
|
|||||||
if (params.refresh) {
|
if (params.refresh) {
|
||||||
this.refresh = params.refresh || this.refresh;
|
this.refresh = params.refresh || this.refresh;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
private routeUpdated() {
|
private routeUpdated() {
|
||||||
var params = this.$location.search();
|
var params = this.$location.search();
|
||||||
@@ -154,7 +154,7 @@ class TimeSrv {
|
|||||||
|
|
||||||
private cancelNextRefresh() {
|
private cancelNextRefresh() {
|
||||||
this.timer.cancel(this.refreshTimer);
|
this.timer.cancel(this.refreshTimer);
|
||||||
};
|
}
|
||||||
|
|
||||||
setTime(time, fromRouteUpdate?) {
|
setTime(time, fromRouteUpdate?) {
|
||||||
_.extend(this.time, time);
|
_.extend(this.time, time);
|
||||||
@@ -184,8 +184,8 @@ class TimeSrv {
|
|||||||
timeRangeForUrl() {
|
timeRangeForUrl() {
|
||||||
var range = this.timeRange().raw;
|
var range = this.timeRange().raw;
|
||||||
|
|
||||||
if (moment.isMoment(range.from)) { range.from = range.from.valueOf(); }
|
if (moment.isMoment(range.from)) { range.from = range.from.valueOf().toString(); }
|
||||||
if (moment.isMoment(range.to)) { range.to = range.to.valueOf(); }
|
if (moment.isMoment(range.to)) { range.to = range.to.valueOf().toString(); }
|
||||||
|
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
skipDataOnInit: boolean;
|
skipDataOnInit: boolean;
|
||||||
dataStream: any;
|
dataStream: any;
|
||||||
dataSubscription: any;
|
dataSubscription: any;
|
||||||
|
dataList: any;
|
||||||
|
|
||||||
constructor($scope, $injector) {
|
constructor($scope, $injector) {
|
||||||
super($scope, $injector);
|
super($scope, $injector);
|
||||||
@@ -106,6 +107,16 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.error = err.message || "Request Error";
|
this.error = err.message || "Request Error";
|
||||||
this.inspector = {error: err};
|
this.inspector = {error: err};
|
||||||
|
|
||||||
|
if (err.data) {
|
||||||
|
if (err.data.message) {
|
||||||
|
this.error = err.data.message;
|
||||||
|
}
|
||||||
|
if (err.data.error) {
|
||||||
|
this.error = err.data.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.events.emit('data-error', err);
|
this.events.emit('data-error', err);
|
||||||
console.log('Panel data error:', err);
|
console.log('Panel data error:', err);
|
||||||
});
|
});
|
||||||
@@ -136,7 +147,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
this.calculateInterval();
|
this.calculateInterval();
|
||||||
|
|
||||||
return this.datasource;
|
return this.datasource;
|
||||||
};
|
}
|
||||||
|
|
||||||
calculateInterval() {
|
calculateInterval() {
|
||||||
var intervalOverride = this.panel.interval;
|
var intervalOverride = this.panel.interval;
|
||||||
@@ -194,7 +205,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
if (this.panel.hideTimeOverride) {
|
if (this.panel.hideTimeOverride) {
|
||||||
this.timeInfo = '';
|
this.timeInfo = '';
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
issueQueries(datasource) {
|
issueQueries(datasource) {
|
||||||
this.datasource = datasource;
|
this.datasource = datasource;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
<div class="gf-form-query">
|
<div class="gf-form-query">
|
||||||
<div class="gf-form">
|
<div class="gf-form gf-form-query-letter-cell">
|
||||||
<label class="gf-form-label gf-form-query-letter-cell">
|
<label class="gf-form-label">
|
||||||
<a class="pointer" tabindex="1" ng-click="ctrl.toggleCollapse()">
|
<a class="pointer" tabindex="1" ng-click="ctrl.toggleCollapse()">
|
||||||
<span ng-class="{muted: !ctrl.canCollapse}" class="gf-form-query-letter-cell-carret">
|
<span ng-class="{muted: !ctrl.canCollapse}" class="gf-form-query-letter-cell-carret">
|
||||||
<i class="fa fa-caret-down" ng-hide="ctrl.collapsed"></i>
|
<i class="fa fa-caret-down" ng-hide="ctrl.collapsed"></i>
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export class PlaylistEditCtrl {
|
|||||||
return playlistItem === listedPlaylistItem;
|
return playlistItem === listedPlaylistItem;
|
||||||
});
|
});
|
||||||
this.filterFoundPlaylistItems();
|
this.filterFoundPlaylistItems();
|
||||||
};
|
}
|
||||||
|
|
||||||
savePlaylist(playlist, playlistItems) {
|
savePlaylist(playlist, playlistItems) {
|
||||||
var savePromise;
|
var savePromise;
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ export class DataSourceEditCtrl {
|
|||||||
this.$location.path('datasources/edit/' + result.id);
|
this.$location.path('datasources/edit/' + result.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
confirmDelete() {
|
confirmDelete() {
|
||||||
this.backendSrv.delete('/api/datasources/' + this.current.id).then(() => {
|
this.backendSrv.delete('/api/datasources/' + this.current.id).then(() => {
|
||||||
|
|||||||
@@ -17,4 +17,4 @@ export {
|
|||||||
CustomVariable,
|
CustomVariable,
|
||||||
ConstantVariable,
|
ConstantVariable,
|
||||||
AdhocVariable,
|
AdhocVariable,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export class VariableSrv {
|
|||||||
|
|
||||||
addVariable(model) {
|
addVariable(model) {
|
||||||
var variable = this.createVariableFromModel(model);
|
var variable = this.createVariableFromModel(model);
|
||||||
this.variables.push(this.createVariableFromModel(variable));
|
this.variables.push(variable);
|
||||||
return variable;
|
return variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ function (angular, _) {
|
|||||||
query = $scope.datasource.getDimensionKeys($scope.target.namespace, $scope.target.region);
|
query = $scope.datasource.getDimensionKeys($scope.target.namespace, $scope.target.region);
|
||||||
} else if (segment.type === 'value') {
|
} else if (segment.type === 'value') {
|
||||||
var dimensionKey = $scope.dimSegments[$index-2].value;
|
var dimensionKey = $scope.dimSegments[$index-2].value;
|
||||||
query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, dimensionKey, {});
|
query = $scope.datasource.getDimensionValues(target.region, target.namespace, target.metricName, dimensionKey, target.dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return query.then($scope.transformToSegments(true)).then(function(results) {
|
return query.then($scope.transformToSegments(true)).then(function(results) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class GrafanaDatasource {
|
|||||||
|
|
||||||
metricFindQuery() {
|
metricFindQuery() {
|
||||||
return this.$q.when([]);
|
return this.$q.when([]);
|
||||||
};
|
}
|
||||||
|
|
||||||
annotationQuery(options) {
|
annotationQuery(options) {
|
||||||
return this.backendSrv.get('/api/annotations', {
|
return this.backendSrv.get('/api/annotations', {
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ export default class InfluxDatasource {
|
|||||||
|
|
||||||
return {data: seriesList};
|
return {data: seriesList};
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
annotationQuery(options) {
|
annotationQuery(options) {
|
||||||
if (!options.annotation.query) {
|
if (!options.annotation.query) {
|
||||||
@@ -137,7 +137,7 @@ export default class InfluxDatasource {
|
|||||||
}
|
}
|
||||||
return new InfluxSeries({series: data.results[0].series, annotation: options.annotation}).getAnnotations();
|
return new InfluxSeries({series: data.results[0].series, annotation: options.annotation}).getAnnotations();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
targetContainsTemplate(target) {
|
targetContainsTemplate(target) {
|
||||||
for (let group of target.groupBy) {
|
for (let group of target.groupBy) {
|
||||||
@@ -155,7 +155,7 @@ export default class InfluxDatasource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
metricFindQuery(query: string, options?: any) {
|
metricFindQuery(query: string, options?: any) {
|
||||||
var interpolated = this.templateSrv.replace(query, null, 'regex');
|
var interpolated = this.templateSrv.replace(query, null, 'regex');
|
||||||
@@ -256,7 +256,7 @@ export default class InfluxDatasource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
getTimeFilter(options) {
|
getTimeFilter(options) {
|
||||||
var from = this.getInfluxTime(options.rangeRaw.from, false);
|
var from = this.getInfluxTime(options.rangeRaw.from, false);
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ export default class InfluxQuery {
|
|||||||
|
|
||||||
var escapedValues = _.map(value, kbn.regexEscape);
|
var escapedValues = _.map(value, kbn.regexEscape);
|
||||||
return escapedValues.join('|');
|
return escapedValues.join('|');
|
||||||
};
|
}
|
||||||
|
|
||||||
render(interpolate?) {
|
render(interpolate?) {
|
||||||
var target = this.target;
|
var target = this.target;
|
||||||
|
|||||||
@@ -91,7 +91,13 @@ function (_) {
|
|||||||
query += ' WHERE ' + whereConditions.join(' ');
|
query += ' WHERE ' + whereConditions.join(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (type === 'MEASUREMENTS')
|
||||||
|
{
|
||||||
|
query += ' LIMIT 100';
|
||||||
|
//Solve issue #2524 by limiting the number of measurements returned
|
||||||
|
//LIMIT must be after WITH MEASUREMENT and WHERE clauses
|
||||||
|
//This also could be used for TAG KEYS and TAG VALUES, if desired
|
||||||
|
}
|
||||||
return query;
|
return query;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ function createPart(part): any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new QueryPart(part, def);
|
return new QueryPart(part, def);
|
||||||
};
|
}
|
||||||
|
|
||||||
function register(options: any) {
|
function register(options: any) {
|
||||||
index[options.type] = new QueryPartDef(options);
|
index[options.type] = new QueryPartDef(options);
|
||||||
|
|||||||
@@ -34,31 +34,31 @@ describe('InfluxQueryBuilder', function() {
|
|||||||
it('should have no conditions in measurement query for query with no tags', function() {
|
it('should have no conditions in measurement query for query with no tags', function() {
|
||||||
var builder = new InfluxQueryBuilder({ measurement: '', tags: [] });
|
var builder = new InfluxQueryBuilder({ measurement: '', tags: [] });
|
||||||
var query = builder.buildExploreQuery('MEASUREMENTS');
|
var query = builder.buildExploreQuery('MEASUREMENTS');
|
||||||
expect(query).to.be('SHOW MEASUREMENTS');
|
expect(query).to.be('SHOW MEASUREMENTS LIMIT 100');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have no conditions in measurement query for query with no tags and empty query', function() {
|
it('should have no conditions in measurement query for query with no tags and empty query', function() {
|
||||||
var builder = new InfluxQueryBuilder({ measurement: '', tags: [] });
|
var builder = new InfluxQueryBuilder({ measurement: '', tags: [] });
|
||||||
var query = builder.buildExploreQuery('MEASUREMENTS', undefined, '');
|
var query = builder.buildExploreQuery('MEASUREMENTS', undefined, '');
|
||||||
expect(query).to.be('SHOW MEASUREMENTS');
|
expect(query).to.be('SHOW MEASUREMENTS LIMIT 100');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have WITH MEASUREMENT in measurement query for non-empty query with no tags', function() {
|
it('should have WITH MEASUREMENT in measurement query for non-empty query with no tags', function() {
|
||||||
var builder = new InfluxQueryBuilder({ measurement: '', tags: [] });
|
var builder = new InfluxQueryBuilder({ measurement: '', tags: [] });
|
||||||
var query = builder.buildExploreQuery('MEASUREMENTS', undefined, 'something');
|
var query = builder.buildExploreQuery('MEASUREMENTS', undefined, 'something');
|
||||||
expect(query).to.be('SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/');
|
expect(query).to.be('SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/ LIMIT 100');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have WITH MEASUREMENT WHERE in measurement query for non-empty query with tags', function() {
|
it('should have WITH MEASUREMENT WHERE in measurement query for non-empty query with tags', function() {
|
||||||
var builder = new InfluxQueryBuilder({ measurement: '', tags: [{key: 'app', value: 'email'}] });
|
var builder = new InfluxQueryBuilder({ measurement: '', tags: [{key: 'app', value: 'email'}] });
|
||||||
var query = builder.buildExploreQuery('MEASUREMENTS', undefined, 'something');
|
var query = builder.buildExploreQuery('MEASUREMENTS', undefined, 'something');
|
||||||
expect(query).to.be("SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/ WHERE \"app\" = 'email'");
|
expect(query).to.be("SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/ WHERE \"app\" = 'email' LIMIT 100");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have where condition in measurement query for query with tags', function() {
|
it('should have where condition in measurement query for query with tags', function() {
|
||||||
var builder = new InfluxQueryBuilder({measurement: '', tags: [{key: 'app', value: 'email'}]});
|
var builder = new InfluxQueryBuilder({measurement: '', tags: [{key: 'app', value: 'email'}]});
|
||||||
var query = builder.buildExploreQuery('MEASUREMENTS');
|
var query = builder.buildExploreQuery('MEASUREMENTS');
|
||||||
expect(query).to.be("SHOW MEASUREMENTS WHERE \"app\" = 'email'");
|
expect(query).to.be("SHOW MEASUREMENTS WHERE \"app\" = 'email' LIMIT 100");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have where tag name IN filter in tag values query for query with one tag', function() {
|
it('should have where tag name IN filter in tag values query for query with one tag', function() {
|
||||||
|
|||||||
@@ -30,4 +30,4 @@ class MixedDatasource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {MixedDatasource, MixedDatasource as Datasource}
|
export {MixedDatasource, MixedDatasource as Datasource};
|
||||||
|
|||||||
@@ -6,12 +6,23 @@ export class MysqlDatasource {
|
|||||||
id: any;
|
id: any;
|
||||||
name: any;
|
name: any;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject **/
|
||||||
constructor(instanceSettings, private backendSrv, private $q) {
|
constructor(instanceSettings, private backendSrv, private $q, private templateSrv) {
|
||||||
this.name = instanceSettings.name;
|
this.name = instanceSettings.name;
|
||||||
this.id = instanceSettings.id;
|
this.id = instanceSettings.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interpolateVariable(value) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return '\"' + value + '\"';
|
||||||
|
}
|
||||||
|
|
||||||
|
var quotedValues = _.map(value, function(val) {
|
||||||
|
return '\"' + val + '\"';
|
||||||
|
});
|
||||||
|
return quotedValues.join(',');
|
||||||
|
}
|
||||||
|
|
||||||
query(options) {
|
query(options) {
|
||||||
var queries = _.filter(options.targets, item => {
|
var queries = _.filter(options.targets, item => {
|
||||||
return item.hide !== true;
|
return item.hide !== true;
|
||||||
@@ -21,7 +32,8 @@ export class MysqlDatasource {
|
|||||||
intervalMs: options.intervalMs,
|
intervalMs: options.intervalMs,
|
||||||
maxDataPoints: options.maxDataPoints,
|
maxDataPoints: options.maxDataPoints,
|
||||||
datasourceId: this.id,
|
datasourceId: this.id,
|
||||||
rawSql: item.rawSql,
|
rawSql: this.templateSrv.replace(item.rawSql, options.scopedVars, this.interpolateVariable),
|
||||||
|
format: item.format,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -29,32 +41,49 @@ export class MysqlDatasource {
|
|||||||
return this.$q.when({data: []});
|
return this.$q.when({data: []});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.backendSrv.post('/api/tsdb/query', {
|
return this.backendSrv.datasourceRequest({
|
||||||
from: options.range.from.valueOf().toString(),
|
url: '/api/tsdb/query',
|
||||||
to: options.range.to.valueOf().toString(),
|
method: 'POST',
|
||||||
queries: queries,
|
data: {
|
||||||
}).then(res => {
|
from: options.range.from.valueOf().toString(),
|
||||||
console.log('mysql response', res);
|
to: options.range.to.valueOf().toString(),
|
||||||
|
queries: queries,
|
||||||
|
}
|
||||||
|
}).then(this.processQueryResult.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
var data = [];
|
processQueryResult(res) {
|
||||||
if (res.results) {
|
var data = [];
|
||||||
_.forEach(res.results, queryRes => {
|
|
||||||
|
|
||||||
if (queryRes.error) {
|
if (!res.data.results) {
|
||||||
throw {error: queryRes.error, message: queryRes.error};
|
return {data: data};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let series of queryRes.series) {
|
for (let key in res.data.results) {
|
||||||
data.push({
|
let queryRes = res.data.results[key];
|
||||||
target: series.name,
|
|
||||||
datapoints: series.points
|
if (queryRes.series) {
|
||||||
});
|
for (let series of queryRes.series) {
|
||||||
}
|
data.push({
|
||||||
});
|
target: series.name,
|
||||||
|
datapoints: series.points,
|
||||||
|
refId: queryRes.refId,
|
||||||
|
meta: queryRes.meta,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {data: data};
|
if (queryRes.tables) {
|
||||||
});
|
for (let table of queryRes.tables) {
|
||||||
|
table.type = 'table';
|
||||||
|
table.refId = queryRes.refId;
|
||||||
|
table.meta = queryRes.meta;
|
||||||
|
data.push(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {data: data};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@@ -1,27 +1,9 @@
|
|||||||
///<reference path="../../../headers/common.d.ts" />
|
///<reference path="../../../headers/common.d.ts" />
|
||||||
|
|
||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
|
import _ from 'lodash';
|
||||||
import {MysqlDatasource} from './datasource';
|
import {MysqlDatasource} from './datasource';
|
||||||
import {QueryCtrl} from 'app/plugins/sdk';
|
import {MysqlQueryCtrl} from './query_ctrl';
|
||||||
|
|
||||||
class MysqlQueryCtrl extends QueryCtrl {
|
|
||||||
static templateUrl = 'partials/query.editor.html';
|
|
||||||
|
|
||||||
resultFormats: any;
|
|
||||||
target: any;
|
|
||||||
|
|
||||||
constructor($scope, $injector) {
|
|
||||||
super($scope, $injector);
|
|
||||||
|
|
||||||
this.target.resultFormat = 'time_series';
|
|
||||||
this.target.alias = "{{table}}{{col_3}}";
|
|
||||||
this.resultFormats = [
|
|
||||||
{text: 'Time series', value: 'time_series'},
|
|
||||||
{text: 'Table', value: 'table'},
|
|
||||||
];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MysqlConfigCtrl {
|
class MysqlConfigCtrl {
|
||||||
static templateUrl = 'partials/config.html';
|
static templateUrl = 'partials/config.html';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<query-editor-row query-ctrl="ctrl" can-collapse="false">
|
<query-editor-row query-ctrl="ctrl" can-collapse="false">
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form gf-form--grow">
|
<div class="gf-form gf-form--grow">
|
||||||
<textarea rows="6" class="gf-form-input" ng-model="ctrl.target.rawSql" spellcheck="false" placeholder="query expression" data-min-length=0 data-items=100 ng-model-onblur ng-change="ctrl.panelCtrl.refresh()"></textarea>
|
<textarea rows="10" class="gf-form-input" ng-model="ctrl.target.rawSql" spellcheck="false" placeholder="query expression" data-min-length=0 data-items=100 ng-model-onblur ng-change="ctrl.panelCtrl.refresh()"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -9,17 +9,51 @@
|
|||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label query-keyword">Format as</label>
|
<label class="gf-form-label query-keyword">Format as</label>
|
||||||
<div class="gf-form-select-wrapper">
|
<div class="gf-form-select-wrapper">
|
||||||
<select class="gf-form-input gf-size-auto" ng-model="ctrl.target.resultFormat" ng-options="f.value as f.text for f in ctrl.resultFormats" ng-change="ctrl.refresh()"></select>
|
<select class="gf-form-input gf-size-auto" ng-model="ctrl.target.format" ng-options="f.value as f.text for f in ctrl.formats" ng-change="ctrl.refresh()"></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form max-width-30">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label query-keyword">Name by</label>
|
<label class="gf-form-label query-keyword" ng-click="ctrl.showHelp = !ctrl.showHelp">
|
||||||
<input type="text" class="gf-form-input" ng-model="ctrl.target.alias" spellcheck='false' placeholder="pattern" ng-blur="ctrl.refresh()">
|
Show Help
|
||||||
|
<i class="fa fa-caret-down" ng-show="ctrl.showHelp"></i>
|
||||||
|
<i class="fa fa-caret-right" ng-hide="ctrl.showHelp"></i>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form" ng-show="ctrl.lastQueryMeta">
|
||||||
|
<label class="gf-form-label query-keyword" ng-click="ctrl.showLastQuerySQL = !ctrl.showLastQuerySQL">
|
||||||
|
Generated SQL
|
||||||
|
<i class="fa fa-caret-down" ng-show="ctrl.showLastQuerySQL"></i>
|
||||||
|
<i class="fa fa-caret-right" ng-hide="ctrl.showLastQuerySQL"></i>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form gf-form--grow">
|
<div class="gf-form gf-form--grow">
|
||||||
<div class="gf-form-label gf-form-label--grow"></div>
|
<div class="gf-form-label gf-form-label--grow"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form" ng-show="ctrl.showLastQuerySQL">
|
||||||
|
<pre class="gf-form-pre">{{ctrl.lastQueryMeta.sql}}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form" ng-show="ctrl.showHelp">
|
||||||
|
<pre class="gf-form-pre alert alert-info">Time series:
|
||||||
|
- return column named time_sec (UTC in seconds), use UNIX_TIMESTAMP(column)
|
||||||
|
- return column named value for the time point value
|
||||||
|
- return column named metric to represent the series name
|
||||||
|
|
||||||
|
Table:
|
||||||
|
- return any set of columns
|
||||||
|
|
||||||
|
Macros:
|
||||||
|
- $__time(column) -> UNIX_TIMESTAMP(column) as time_sec
|
||||||
|
- $__timeFilter(column) -> UNIX_TIMESTAMP(time_date_time) > from AND UNIX_TIMESTAMP(time_date_time) < 1492750877
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form" ng-show="ctrl.lastQueryError">
|
||||||
|
<pre class="gf-form-pre alert alert-error">{{ctrl.lastQueryError}}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
</query-editor-row>
|
</query-editor-row>
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
///<reference path="../../../headers/common.d.ts" />
|
||||||
|
|
||||||
|
import angular from 'angular';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import {MysqlDatasource} from './datasource';
|
||||||
|
import {QueryCtrl} from 'app/plugins/sdk';
|
||||||
|
|
||||||
|
export interface MysqlQuery {
|
||||||
|
refId: string;
|
||||||
|
format: string;
|
||||||
|
alias: string;
|
||||||
|
rawSql: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QueryMeta {
|
||||||
|
sql: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var defaulQuery = `SELECT
|
||||||
|
UNIX_TIMESTAMP(<time_column>) as time_sec,
|
||||||
|
<value column> as value,
|
||||||
|
<series name column> as metric
|
||||||
|
FROM <table name>
|
||||||
|
WHERE $__timeFilter(time_column)
|
||||||
|
ORDER BY <time_column> ASC
|
||||||
|
`;
|
||||||
|
|
||||||
|
export class MysqlQueryCtrl extends QueryCtrl {
|
||||||
|
static templateUrl = 'partials/query.editor.html';
|
||||||
|
|
||||||
|
showLastQuerySQL: boolean;
|
||||||
|
formats: any[];
|
||||||
|
target: MysqlQuery;
|
||||||
|
lastQueryMeta: QueryMeta;
|
||||||
|
lastQueryError: string;
|
||||||
|
showHelp: boolean;
|
||||||
|
|
||||||
|
/** @ngInject **/
|
||||||
|
constructor($scope, $injector) {
|
||||||
|
super($scope, $injector);
|
||||||
|
|
||||||
|
this.target.format = this.target.format || 'time_series';
|
||||||
|
this.target.alias = "";
|
||||||
|
this.formats = [
|
||||||
|
{text: 'Time series', value: 'time_series'},
|
||||||
|
{text: 'Table', value: 'table'},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!this.target.rawSql) {
|
||||||
|
this.target.rawSql = defaulQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
|
||||||
|
this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDataReceived(dataList) {
|
||||||
|
this.lastQueryMeta = null;
|
||||||
|
this.lastQueryError = null;
|
||||||
|
|
||||||
|
let anySeriesFromQuery = _.find(dataList, {refId: this.target.refId});
|
||||||
|
if (anySeriesFromQuery) {
|
||||||
|
this.lastQueryMeta = anySeriesFromQuery.meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDataError(err) {
|
||||||
|
if (err.data && err.data.results) {
|
||||||
|
let queryRes = err.data.results[this.target.refId];
|
||||||
|
if (queryRes) {
|
||||||
|
this.lastQueryMeta = queryRes.meta;
|
||||||
|
this.lastQueryError = queryRes.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,4 +139,4 @@ class AlertListPanel extends PanelCtrl {
|
|||||||
export {
|
export {
|
||||||
AlertListPanel,
|
AlertListPanel,
|
||||||
AlertListPanel as PanelCtrl
|
AlertListPanel as PanelCtrl
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -125,4 +125,4 @@ class DashListCtrl extends PanelCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {DashListCtrl, DashListCtrl as PanelCtrl}
|
export {DashListCtrl, DashListCtrl as PanelCtrl};
|
||||||
|
|||||||
@@ -116,4 +116,4 @@ class GettingStartedPanelCtrl extends PanelCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {GettingStartedPanelCtrl, GettingStartedPanelCtrl as PanelCtrl}
|
export {GettingStartedPanelCtrl, GettingStartedPanelCtrl as PanelCtrl};
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
var series = data[i];
|
let series = data[i];
|
||||||
series.data = series.getFlotPairs(series.nullPointMode || panel.nullPointMode);
|
series.data = series.getFlotPairs(series.nullPointMode || panel.nullPointMode);
|
||||||
|
|
||||||
// if hidden remove points and disable stack
|
// if hidden remove points and disable stack
|
||||||
@@ -287,7 +287,7 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
|
|||||||
options.series.bars.align = 'center';
|
options.series.bars.align = 'center';
|
||||||
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
var series = data[i];
|
let series = data[i];
|
||||||
series.data = [[i + 1, series.stats[panel.xaxis.values[0]]]];
|
series.data = [[i + 1, series.stats[panel.xaxis.values[0]]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ class GraphCtrl extends MetricsPanelCtrl {
|
|||||||
}
|
}
|
||||||
info.yaxis = override.yaxis = info.yaxis === 2 ? 1 : 2;
|
info.yaxis = override.yaxis = info.yaxis === 2 ? 1 : 2;
|
||||||
this.render();
|
this.render();
|
||||||
};
|
}
|
||||||
|
|
||||||
addSeriesOverride(override) {
|
addSeriesOverride(override) {
|
||||||
this.panel.seriesOverrides.push(override || {});
|
this.panel.seriesOverrides.push(override || {});
|
||||||
@@ -316,4 +316,4 @@ class GraphCtrl extends MetricsPanelCtrl {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {GraphCtrl, GraphCtrl as PanelCtrl}
|
export {GraphCtrl, GraphCtrl as PanelCtrl};
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ export class AxesEditorCtrl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.dataFormats = {
|
this.dataFormats = {
|
||||||
'Timeseries': 'timeseries',
|
'TS': 'timeseries',
|
||||||
'ES histogram': 'es_histogram'
|
'TS Pre-bucketed': 'tsbuckets'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ export class HeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
let xBucketSize, yBucketSize, heatmapStats, bucketsData;
|
let xBucketSize, yBucketSize, heatmapStats, bucketsData;
|
||||||
let logBase = this.panel.yAxis.logBase;
|
let logBase = this.panel.yAxis.logBase;
|
||||||
|
|
||||||
if (this.panel.dataFormat === 'es_histogram') {
|
if (this.panel.dataFormat === 'tsbuckets') {
|
||||||
heatmapStats = this.parseHistogramSeries(this.series);
|
heatmapStats = this.parseHistogramSeries(this.series);
|
||||||
bucketsData = elasticHistogramToHeatmap(this.series);
|
bucketsData = elasticHistogramToHeatmap(this.series);
|
||||||
|
|
||||||
|
|||||||
@@ -70,4 +70,4 @@ class PluginListCtrl extends PanelCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {PluginListCtrl, PluginListCtrl as PanelCtrl}
|
export {PluginListCtrl, PluginListCtrl as PanelCtrl};
|
||||||
|
|||||||
@@ -3,11 +3,19 @@
|
|||||||
<h5 class="section-heading">Value</h5>
|
<h5 class="section-heading">Value</h5>
|
||||||
|
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form">
|
<div class="gf-form" ng-show="ctrl.dataType === 'timeseries'">
|
||||||
<label class="gf-form-label width-6">Stat</label>
|
<label class="gf-form-label width-6">Stat</label>
|
||||||
<div class="gf-form-select-wrapper width-7">
|
<div class="gf-form-select-wrapper width-7">
|
||||||
<select class="gf-form-input" ng-model="ctrl.panel.valueName" ng-options="f for f in ctrl.valueNameOptions" ng-change="ctrl.render()"></select>
|
<select class="gf-form-input" ng-model="ctrl.panel.valueName" ng-options="f for f in ctrl.valueNameOptions" ng-change="ctrl.render()"></select>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form" ng-show="ctrl.dataType === 'table'">
|
||||||
|
<label class="gf-form-label width-6">Column</label>
|
||||||
|
<div class="gf-form-select-wrapper width-7">
|
||||||
|
<select class="gf-form-input" ng-model="ctrl.panel.tableColumn" ng-options="f for f in ctrl.tableColumnOptions" ng-change="ctrl.refresh()"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-6">Font size</label>
|
<label class="gf-form-label width-6">Font size</label>
|
||||||
<div class="gf-form-select-wrapper">
|
<div class="gf-form-select-wrapper">
|
||||||
<select class="gf-form-input" ng-model="ctrl.panel.valueFontSize" ng-options="f for f in ctrl.fontSizes" ng-change="ctrl.render()"></select>
|
<select class="gf-form-input" ng-model="ctrl.panel.valueFontSize" ng-options="f for f in ctrl.fontSizes" ng-change="ctrl.render()"></select>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {MetricsPanelCtrl} from 'app/plugins/sdk';
|
|||||||
class SingleStatCtrl extends MetricsPanelCtrl {
|
class SingleStatCtrl extends MetricsPanelCtrl {
|
||||||
static templateUrl = 'module.html';
|
static templateUrl = 'module.html';
|
||||||
|
|
||||||
|
dataType = 'timeseries';
|
||||||
series: any[];
|
series: any[];
|
||||||
data: any;
|
data: any;
|
||||||
fontSizes: any[];
|
fontSizes: any[];
|
||||||
@@ -22,6 +23,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
panel: any;
|
panel: any;
|
||||||
events: any;
|
events: any;
|
||||||
valueNameOptions: any[] = ['min','max','avg', 'current', 'total', 'name', 'first', 'delta', 'diff', 'range'];
|
valueNameOptions: any[] = ['min','max','avg', 'current', 'total', 'name', 'first', 'delta', 'diff', 'range'];
|
||||||
|
tableColumnOptions: any;
|
||||||
|
|
||||||
// Set and populate defaults
|
// Set and populate defaults
|
||||||
panelDefaults = {
|
panelDefaults = {
|
||||||
@@ -67,7 +69,8 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
maxValue: 100,
|
maxValue: 100,
|
||||||
thresholdMarkers: true,
|
thresholdMarkers: true,
|
||||||
thresholdLabels: false
|
thresholdLabels: false
|
||||||
}
|
},
|
||||||
|
tableColumn: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
@@ -98,11 +101,16 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onDataReceived(dataList) {
|
onDataReceived(dataList) {
|
||||||
this.series = dataList.map(this.seriesHandler.bind(this));
|
const data: any = {};
|
||||||
|
if (dataList.length > 0 && dataList[0].type === 'table'){
|
||||||
var data: any = {};
|
this.dataType = 'table';
|
||||||
this.setValues(data);
|
const tableData = dataList.map(this.tableHandler.bind(this));
|
||||||
|
this.setTableValues(tableData, data);
|
||||||
|
} else {
|
||||||
|
this.dataType = 'timeseries';
|
||||||
|
this.series = dataList.map(this.seriesHandler.bind(this));
|
||||||
|
this.setValues(data);
|
||||||
|
}
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
@@ -117,6 +125,69 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
return series;
|
return series;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tableHandler(tableData) {
|
||||||
|
const datapoints = [];
|
||||||
|
const columnNames = {};
|
||||||
|
|
||||||
|
tableData.columns.forEach((column, columnIndex) => {
|
||||||
|
columnNames[columnIndex] = column.text;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tableColumnOptions = columnNames;
|
||||||
|
if (!_.find(tableData.columns, ['text', this.panel.tableColumn])) {
|
||||||
|
this.setTableColumnToSensibleDefault(tableData);
|
||||||
|
}
|
||||||
|
|
||||||
|
tableData.rows.forEach((row) => {
|
||||||
|
const datapoint = {};
|
||||||
|
|
||||||
|
row.forEach((value, columnIndex) => {
|
||||||
|
const key = columnNames[columnIndex];
|
||||||
|
datapoint[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
datapoints.push(datapoint);
|
||||||
|
});
|
||||||
|
|
||||||
|
return datapoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTableColumnToSensibleDefault(tableData) {
|
||||||
|
if (this.tableColumnOptions.length === 1) {
|
||||||
|
this.panel.tableColumn = this.tableColumnOptions[0];
|
||||||
|
} else {
|
||||||
|
this.panel.tableColumn = _.find(tableData.columns, (col) => { return col.type !== 'time'; }).text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTableValues(tableData, data) {
|
||||||
|
if (!tableData || tableData.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tableData[0].length === 0 || !tableData[0][0][this.panel.tableColumn]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let highestValue = 0;
|
||||||
|
let lowestValue = Number.MAX_VALUE;
|
||||||
|
const datapoint = tableData[0][0];
|
||||||
|
data.value = datapoint[this.panel.tableColumn];
|
||||||
|
|
||||||
|
if (_.isString(data.value)) {
|
||||||
|
data.valueFormatted = _.escape(data.value);
|
||||||
|
data.value = 0;
|
||||||
|
data.valueRounded = 0;
|
||||||
|
} else {
|
||||||
|
const decimalInfo = this.getDecimalsForValue(data.value);
|
||||||
|
const formatFunc = kbn.valueFormats[this.panel.format];
|
||||||
|
data.valueFormatted = formatFunc(datapoint[this.panel.tableColumn], decimalInfo.decimals, decimalInfo.scaledDecimals);
|
||||||
|
data.valueRounded = kbn.roundValue(data.value, this.panel.decimals || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setValueMapping(data);
|
||||||
|
}
|
||||||
|
|
||||||
setColoring(options) {
|
setColoring(options) {
|
||||||
if (options.background) {
|
if (options.background) {
|
||||||
this.panel.colorValue = false;
|
this.panel.colorValue = false;
|
||||||
@@ -192,10 +263,10 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
if (this.panel.valueName === 'name') {
|
if (this.panel.valueName === 'name') {
|
||||||
data.value = 0;
|
data.value = 0;
|
||||||
data.valueRounded = 0;
|
data.valueRounded = 0;
|
||||||
data.valueFormated = this.series[0].alias;
|
data.valueFormatted = this.series[0].alias;
|
||||||
} else if (_.isString(lastValue)) {
|
} else if (_.isString(lastValue)) {
|
||||||
data.value = 0;
|
data.value = 0;
|
||||||
data.valueFormated = _.escape(lastValue);
|
data.valueFormatted = _.escape(lastValue);
|
||||||
data.valueRounded = 0;
|
data.valueRounded = 0;
|
||||||
} else {
|
} else {
|
||||||
data.value = this.series[0].stats[this.panel.valueName];
|
data.value = this.series[0].stats[this.panel.valueName];
|
||||||
@@ -203,7 +274,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
|
|
||||||
var decimalInfo = this.getDecimalsForValue(data.value);
|
var decimalInfo = this.getDecimalsForValue(data.value);
|
||||||
var formatFunc = kbn.valueFormats[this.panel.format];
|
var formatFunc = kbn.valueFormats[this.panel.format];
|
||||||
data.valueFormated = formatFunc(data.value, decimalInfo.decimals, decimalInfo.scaledDecimals);
|
data.valueFormatted = formatFunc(data.value, decimalInfo.decimals, decimalInfo.scaledDecimals);
|
||||||
data.valueRounded = kbn.roundValue(data.value, decimalInfo.decimals);
|
data.valueRounded = kbn.roundValue(data.value, decimalInfo.decimals);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,15 +282,18 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
data.scopedVars = _.extend({}, this.panel.scopedVars);
|
data.scopedVars = _.extend({}, this.panel.scopedVars);
|
||||||
data.scopedVars["__name"] = {value: this.series[0].label};
|
data.scopedVars["__name"] = {value: this.series[0].label};
|
||||||
}
|
}
|
||||||
|
this.setValueMapping(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
setValueMapping(data) {
|
||||||
// check value to text mappings if its enabled
|
// check value to text mappings if its enabled
|
||||||
if (this.panel.mappingType === 1) {
|
if (this.panel.mappingType === 1) {
|
||||||
for (var i = 0; i < this.panel.valueMaps.length; i++) {
|
for (let i = 0; i < this.panel.valueMaps.length; i++) {
|
||||||
var map = this.panel.valueMaps[i];
|
let map = this.panel.valueMaps[i];
|
||||||
// special null case
|
// special null case
|
||||||
if (map.value === 'null') {
|
if (map.value === 'null') {
|
||||||
if (data.value === null || data.value === void 0) {
|
if (data.value === null || data.value === void 0) {
|
||||||
data.valueFormated = map.text;
|
data.valueFormatted = map.text;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -228,17 +302,17 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
// value/number to text mapping
|
// value/number to text mapping
|
||||||
var value = parseFloat(map.value);
|
var value = parseFloat(map.value);
|
||||||
if (value === data.valueRounded) {
|
if (value === data.valueRounded) {
|
||||||
data.valueFormated = map.text;
|
data.valueFormatted = map.text;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (this.panel.mappingType === 2) {
|
} else if (this.panel.mappingType === 2) {
|
||||||
for (var i = 0; i < this.panel.rangeMaps.length; i++) {
|
for (let i = 0; i < this.panel.rangeMaps.length; i++) {
|
||||||
var map = this.panel.rangeMaps[i];
|
let map = this.panel.rangeMaps[i];
|
||||||
// special null case
|
// special null case
|
||||||
if (map.from === 'null' && map.to === 'null') {
|
if (map.from === 'null' && map.to === 'null') {
|
||||||
if (data.value === null || data.value === void 0) {
|
if (data.value === null || data.value === void 0) {
|
||||||
data.valueFormated = map.text;
|
data.valueFormatted = map.text;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -248,22 +322,22 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
var from = parseFloat(map.from);
|
var from = parseFloat(map.from);
|
||||||
var to = parseFloat(map.to);
|
var to = parseFloat(map.to);
|
||||||
if (to >= data.valueRounded && from <= data.valueRounded) {
|
if (to >= data.valueRounded && from <= data.valueRounded) {
|
||||||
data.valueFormated = map.text;
|
data.valueFormatted = map.text;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.value === null || data.value === void 0) {
|
if (data.value === null || data.value === void 0) {
|
||||||
data.valueFormated = "no value";
|
data.valueFormatted = "no value";
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
removeValueMap(map) {
|
removeValueMap(map) {
|
||||||
var index = _.indexOf(this.panel.valueMaps, map);
|
var index = _.indexOf(this.panel.valueMaps, map);
|
||||||
this.panel.valueMaps.splice(index, 1);
|
this.panel.valueMaps.splice(index, 1);
|
||||||
this.render();
|
this.render();
|
||||||
};
|
}
|
||||||
|
|
||||||
addValueMap() {
|
addValueMap() {
|
||||||
this.panel.valueMaps.push({value: '', op: '=', text: '' });
|
this.panel.valueMaps.push({value: '', op: '=', text: '' });
|
||||||
@@ -273,7 +347,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
var index = _.indexOf(this.panel.rangeMaps, rangeMap);
|
var index = _.indexOf(this.panel.rangeMaps, rangeMap);
|
||||||
this.panel.rangeMaps.splice(index, 1);
|
this.panel.rangeMaps.splice(index, 1);
|
||||||
this.render();
|
this.render();
|
||||||
};
|
}
|
||||||
|
|
||||||
addRangeMap() {
|
addRangeMap() {
|
||||||
this.panel.rangeMaps.push({from: '', to: '', text: ''});
|
this.panel.rangeMaps.push({from: '', to: '', text: ''});
|
||||||
@@ -317,7 +391,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
|
|
||||||
if (panel.prefix) { body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, panel.prefix); }
|
if (panel.prefix) { body += getSpan('singlestat-panel-prefix', panel.prefixFontSize, panel.prefix); }
|
||||||
|
|
||||||
var value = applyColoringThresholds(data.value, data.valueFormated);
|
var value = applyColoringThresholds(data.value, data.valueFormatted);
|
||||||
body += getSpan('singlestat-panel-value', panel.valueFontSize, value);
|
body += getSpan('singlestat-panel-value', panel.valueFontSize, value);
|
||||||
|
|
||||||
if (panel.postfix) { body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, panel.postfix); }
|
if (panel.postfix) { body += getSpan('singlestat-panel-postfix', panel.postfixFontSize, panel.postfix); }
|
||||||
@@ -329,7 +403,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
|
|||||||
|
|
||||||
function getValueText() {
|
function getValueText() {
|
||||||
var result = panel.prefix ? panel.prefix : '';
|
var result = panel.prefix ? panel.prefix : '';
|
||||||
result += data.valueFormated;
|
result += data.valueFormatted;
|
||||||
result += panel.postfix ? panel.postfix : '';
|
result += panel.postfix ? panel.postfix : '';
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
///<reference path="../../../../headers/common.d.ts" />
|
|
||||||
|
|
||||||
import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
|
|
||||||
|
|
||||||
import angular from 'angular';
|
|
||||||
import helpers from '../../../../../test/specs/helpers';
|
|
||||||
import {SingleStatCtrl} from '../module';
|
|
||||||
|
|
||||||
describe('SingleStatCtrl', function() {
|
|
||||||
var ctx = new helpers.ControllerTestContext();
|
|
||||||
|
|
||||||
function singleStatScenario(desc, func) {
|
|
||||||
|
|
||||||
describe(desc, function() {
|
|
||||||
|
|
||||||
ctx.setup = function (setupFunc) {
|
|
||||||
|
|
||||||
beforeEach(angularMocks.module('grafana.services'));
|
|
||||||
beforeEach(angularMocks.module('grafana.controllers'));
|
|
||||||
beforeEach(angularMocks.module(function($compileProvider) {
|
|
||||||
$compileProvider.preAssignBindingsEnabled(true);
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(ctx.providePhase());
|
|
||||||
beforeEach(ctx.createPanelController(SingleStatCtrl));
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
setupFunc();
|
|
||||||
var data = [
|
|
||||||
{target: 'test.cpu1', datapoints: ctx.datapoints}
|
|
||||||
];
|
|
||||||
|
|
||||||
ctx.ctrl.onDataReceived(data);
|
|
||||||
ctx.data = ctx.ctrl.data;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
func(ctx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
singleStatScenario('with defaults', function(ctx) {
|
|
||||||
ctx.setup(function() {
|
|
||||||
ctx.datapoints = [[10,1], [20,2]];
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should use series avg as default main value', function() {
|
|
||||||
expect(ctx.data.value).to.be(15);
|
|
||||||
expect(ctx.data.valueRounded).to.be(15);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set formated falue', function() {
|
|
||||||
expect(ctx.data.valueFormated).to.be('15');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
singleStatScenario('showing serie name instead of value', function(ctx) {
|
|
||||||
ctx.setup(function() {
|
|
||||||
ctx.datapoints = [[10,1], [20,2]];
|
|
||||||
ctx.ctrl.panel.valueName = 'name';
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should use series avg as default main value', function() {
|
|
||||||
expect(ctx.data.value).to.be(0);
|
|
||||||
expect(ctx.data.valueRounded).to.be(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set formated falue', function() {
|
|
||||||
expect(ctx.data.valueFormated).to.be('test.cpu1');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
singleStatScenario('MainValue should use same number for decimals as displayed when checking thresholds', function(ctx) {
|
|
||||||
ctx.setup(function() {
|
|
||||||
ctx.datapoints = [[99.999,1], [99.99999,2]];
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be rounded', function() {
|
|
||||||
expect(ctx.data.value).to.be(99.999495);
|
|
||||||
expect(ctx.data.valueRounded).to.be(100);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set formated falue', function() {
|
|
||||||
expect(ctx.data.valueFormated).to.be('100');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
singleStatScenario('When value to text mapping is specified', function(ctx) {
|
|
||||||
ctx.setup(function() {
|
|
||||||
ctx.datapoints = [[9.9,1]];
|
|
||||||
ctx.ctrl.panel.valueMaps = [{value: '10', text: 'OK'}];
|
|
||||||
});
|
|
||||||
|
|
||||||
it('value should remain', function() {
|
|
||||||
expect(ctx.data.value).to.be(9.9);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('round should be rounded up', function() {
|
|
||||||
expect(ctx.data.valueRounded).to.be(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should replace value with text', function() {
|
|
||||||
expect(ctx.data.valueFormated).to.be('OK');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
singleStatScenario('When range to text mapping is specifiedfor first range', function(ctx) {
|
|
||||||
ctx.setup(function() {
|
|
||||||
ctx.datapoints = [[41,50]];
|
|
||||||
ctx.ctrl.panel.mappingType = 2;
|
|
||||||
ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should replace value with text OK', function() {
|
|
||||||
expect(ctx.data.valueFormated).to.be('OK');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
singleStatScenario('When range to text mapping is specified for other ranges', function(ctx) {
|
|
||||||
ctx.setup(function() {
|
|
||||||
ctx.datapoints = [[65,75]];
|
|
||||||
ctx.ctrl.panel.mappingType = 2;
|
|
||||||
ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should replace value with text NOT OK', function() {
|
|
||||||
expect(ctx.data.valueFormated).to.be('NOT OK');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
///<reference path="../../../../headers/common.d.ts" />
|
||||||
|
|
||||||
|
import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
|
||||||
|
|
||||||
|
import angular from 'angular';
|
||||||
|
import helpers from '../../../../../test/specs/helpers';
|
||||||
|
import {SingleStatCtrl} from '../module';
|
||||||
|
|
||||||
|
describe('SingleStatCtrl', function() {
|
||||||
|
var ctx = new helpers.ControllerTestContext();
|
||||||
|
|
||||||
|
function singleStatScenario(desc, func) {
|
||||||
|
|
||||||
|
describe(desc, function() {
|
||||||
|
|
||||||
|
ctx.setup = function (setupFunc) {
|
||||||
|
|
||||||
|
beforeEach(angularMocks.module('grafana.services'));
|
||||||
|
beforeEach(angularMocks.module('grafana.controllers'));
|
||||||
|
beforeEach(angularMocks.module(function($compileProvider) {
|
||||||
|
$compileProvider.preAssignBindingsEnabled(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(ctx.providePhase());
|
||||||
|
beforeEach(ctx.createPanelController(SingleStatCtrl));
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
setupFunc();
|
||||||
|
ctx.ctrl.onDataReceived(ctx.data);
|
||||||
|
ctx.data = ctx.ctrl.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
func(ctx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
singleStatScenario('with defaults', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = [
|
||||||
|
{target: 'test.cpu1', datapoints: [[10,1], [20,2]]}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should use series avg as default main value', function() {
|
||||||
|
expect(ctx.data.value).to.be(15);
|
||||||
|
expect(ctx.data.valueRounded).to.be(15);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set formatted falue', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('15');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('showing serie name instead of value', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = [
|
||||||
|
{target: 'test.cpu1', datapoints: [[10,1], [20,2]]}
|
||||||
|
];
|
||||||
|
ctx.ctrl.panel.valueName = 'name';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should use series avg as default main value', function() {
|
||||||
|
expect(ctx.data.value).to.be(0);
|
||||||
|
expect(ctx.data.valueRounded).to.be(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set formatted falue', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('test.cpu1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('MainValue should use same number for decimals as displayed when checking thresholds', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = [
|
||||||
|
{target: 'test.cpu1', datapoints: [[99.999,1], [99.99999,2]]}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be rounded', function() {
|
||||||
|
expect(ctx.data.value).to.be(99.999495);
|
||||||
|
expect(ctx.data.valueRounded).to.be(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set formatted falue', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('100');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('When value to text mapping is specified', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = [
|
||||||
|
{target: 'test.cpu1', datapoints: [[9.9,1]]}
|
||||||
|
];
|
||||||
|
ctx.ctrl.panel.valueMaps = [{value: '10', text: 'OK'}];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should remain', function() {
|
||||||
|
expect(ctx.data.value).to.be(9.9);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('round should be rounded up', function() {
|
||||||
|
expect(ctx.data.valueRounded).to.be(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should replace value with text', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('OK');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('When range to text mapping is specifiedfor first range', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = [
|
||||||
|
{target: 'test.cpu1', datapoints: [[41,50]]}
|
||||||
|
];
|
||||||
|
ctx.ctrl.panel.mappingType = 2;
|
||||||
|
ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should replace value with text OK', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('OK');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('When range to text mapping is specified for other ranges', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = [
|
||||||
|
{target: 'test.cpu1', datapoints: [[65,75]]}
|
||||||
|
];
|
||||||
|
ctx.ctrl.panel.mappingType = 2;
|
||||||
|
ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should replace value with text NOT OK', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('NOT OK');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When table data', function() {
|
||||||
|
const tableData = [{
|
||||||
|
"columns": [
|
||||||
|
{ "text": "Time", "type": "time" },
|
||||||
|
{ "text": "test1" },
|
||||||
|
{ "text": "mean" },
|
||||||
|
{ "text": "test2" }
|
||||||
|
],
|
||||||
|
"rows": [
|
||||||
|
[1492759673649, 'ignore1', 15, 'ignore2']
|
||||||
|
],
|
||||||
|
"type": "table"
|
||||||
|
}];
|
||||||
|
|
||||||
|
singleStatScenario('with default values', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = tableData;
|
||||||
|
ctx.ctrl.panel.tableColumn = 'mean';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should use first rows value as default main value', function() {
|
||||||
|
expect(ctx.data.value).to.be(15);
|
||||||
|
expect(ctx.data.valueRounded).to.be(15);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set formatted value', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('15');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('When table data has multiple columns', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = tableData;
|
||||||
|
ctx.ctrl.panel.tableColumn = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should set column to first column that is not time', function() {
|
||||||
|
expect(ctx.ctrl.panel.tableColumn).to.be('test1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('MainValue should use same number for decimals as displayed when checking thresholds', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = tableData;
|
||||||
|
ctx.data[0].rows[0] = [1492759673649,'ignore1', 99.99999, 'ignore2'];
|
||||||
|
ctx.ctrl.panel.tableColumn = 'mean';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be rounded', function() {
|
||||||
|
expect(ctx.data.value).to.be(99.99999);
|
||||||
|
expect(ctx.data.valueRounded).to.be(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set formatted falue', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('100');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('When value to text mapping is specified', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = tableData;
|
||||||
|
ctx.data[0].rows[0] = [1492759673649,'ignore1', 9.9, 'ignore2'];
|
||||||
|
ctx.ctrl.panel.tableColumn = 'mean';
|
||||||
|
ctx.ctrl.panel.valueMaps = [{value: '10', text: 'OK'}];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should remain', function() {
|
||||||
|
expect(ctx.data.value).to.be(9.9);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('round should be rounded up', function() {
|
||||||
|
expect(ctx.data.valueRounded).to.be(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should replace value with text', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('OK');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('When range to text mapping is specified for first range', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = tableData;
|
||||||
|
ctx.data[0].rows[0] = [1492759673649,'ignore1', 41, 'ignore2'];
|
||||||
|
ctx.ctrl.panel.tableColumn = 'mean';
|
||||||
|
ctx.ctrl.panel.mappingType = 2;
|
||||||
|
ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should replace value with text OK', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('OK');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('When range to text mapping is specified for other ranges', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = tableData;
|
||||||
|
ctx.data[0].rows[0] = [1492759673649,'ignore1', 65, 'ignore2'];
|
||||||
|
ctx.ctrl.panel.tableColumn = 'mean';
|
||||||
|
ctx.ctrl.panel.mappingType = 2;
|
||||||
|
ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should replace value with text NOT OK', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('NOT OK');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
singleStatScenario('When value is string', function(ctx) {
|
||||||
|
ctx.setup(function() {
|
||||||
|
ctx.data = tableData;
|
||||||
|
ctx.data[0].rows[0] = [1492759673649,'ignore1', 65, 'ignore2'];
|
||||||
|
ctx.ctrl.panel.tableColumn = 'test1';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should replace value with text NOT OK', function() {
|
||||||
|
expect(ctx.data.valueFormatted).to.be('ignore1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ export class TablePanelEditorCtrl {
|
|||||||
setUnitFormat(column, subItem) {
|
setUnitFormat(column, subItem) {
|
||||||
column.unit = subItem.value;
|
column.unit = subItem.value;
|
||||||
this.panelCtrl.render();
|
this.panelCtrl.render();
|
||||||
};
|
}
|
||||||
|
|
||||||
addColumnStyle() {
|
addColumnStyle() {
|
||||||
var columnStyleDefaults = {
|
var columnStyleDefaults = {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ transformers['timeseries_to_columns'] = {
|
|||||||
// group by time
|
// group by time
|
||||||
var points = {};
|
var points = {};
|
||||||
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
var series = data[i];
|
var series = data[i];
|
||||||
model.columns.push({text: series.target});
|
model.columns.push({text: series.target});
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ transformers['timeseries_to_columns'] = {
|
|||||||
var point = points[time];
|
var point = points[time];
|
||||||
var values = [point.time];
|
var values = [point.time];
|
||||||
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
var value = point[i];
|
var value = point[i];
|
||||||
values.push(value);
|
values.push(value);
|
||||||
}
|
}
|
||||||
@@ -242,4 +242,4 @@ function transformDataToTable(data, panel) {
|
|||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {transformers, transformDataToTable}
|
export {transformers, transformDataToTable};
|
||||||
|
|||||||
@@ -79,4 +79,4 @@ export class TextPanelCtrl extends PanelCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {TextPanelCtrl as PanelCtrl}
|
export {TextPanelCtrl as PanelCtrl};
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ export {
|
|||||||
MetricsPanelCtrl,
|
MetricsPanelCtrl,
|
||||||
QueryCtrl,
|
QueryCtrl,
|
||||||
alertTab,
|
alertTab,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -66,6 +66,16 @@ $gf-form-margin: 0.25rem;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gf-form-pre {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
margin: 0;
|
||||||
|
margin-right: $gf-form-margin;
|
||||||
|
border: $input-btn-border-width solid transparent;
|
||||||
|
@include border-radius($label-border-radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
.gf-form-error {
|
.gf-form-error {
|
||||||
padding: $input-padding-y $input-padding-x;
|
padding: $input-padding-y $input-padding-x;
|
||||||
margin-right: $gf-form-margin;
|
margin-right: $gf-form-margin;
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ export {
|
|||||||
sinon,
|
sinon,
|
||||||
expect,
|
expect,
|
||||||
angularMocks,
|
angularMocks,
|
||||||
}
|
};
|
||||||
|
|||||||
+1
-1
@@ -8,10 +8,10 @@ module.exports = function(grunt) {
|
|||||||
'jshint:source',
|
'jshint:source',
|
||||||
'jshint:tests',
|
'jshint:tests',
|
||||||
'jscs',
|
'jscs',
|
||||||
'exec:tslint',
|
|
||||||
'clean:release',
|
'clean:release',
|
||||||
'copy:node_modules',
|
'copy:node_modules',
|
||||||
'copy:public_to_gen',
|
'copy:public_to_gen',
|
||||||
|
'exec:tslint',
|
||||||
'exec:tscompile',
|
'exec:tscompile',
|
||||||
'karma:test',
|
'karma:test',
|
||||||
'phantomjs',
|
'phantomjs',
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ module.exports = function(grunt) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
grunt.registerTask('default', [
|
grunt.registerTask('default', [
|
||||||
|
'clean:gen',
|
||||||
'jscs',
|
'jscs',
|
||||||
'jshint',
|
'jshint',
|
||||||
'exec:tslint',
|
|
||||||
'clean:gen',
|
|
||||||
'copy:node_modules',
|
'copy:node_modules',
|
||||||
'copy:public_to_gen',
|
'copy:public_to_gen',
|
||||||
|
'exec:tslint',
|
||||||
'phantomjs',
|
'phantomjs',
|
||||||
'css',
|
'css',
|
||||||
'exec:tscompile'
|
'exec:tscompile'
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
module.exports = function(config, grunt) {
|
module.exports = function(config, grunt) {
|
||||||
'use strict'
|
'use strict'
|
||||||
return {
|
return {
|
||||||
tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json",
|
tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json --type-check",
|
||||||
tslintfile : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json <%= tslint.source.files.src %>",
|
tslintfile : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json --type-check <%= tslint.source.files.src %>",
|
||||||
tscompile: "node ./node_modules/typescript/lib/tsc.js -p tsconfig.json --diagnostics",
|
tscompile: "node ./node_modules/typescript/lib/tsc.js -p tsconfig.json --diagnostics",
|
||||||
tswatch: "node ./node_modules/typescript/lib/tsc.js -p tsconfig.json --diagnostics --watch",
|
tswatch: "node ./node_modules/typescript/lib/tsc.js -p tsconfig.json --diagnostics --watch",
|
||||||
};
|
};
|
||||||
|
|||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
package mysql
|
||||||
|
|
||||||
|
const (
|
||||||
|
// In case we get something unexpected
|
||||||
|
FieldTypeUnknown = "UNKNOWN"
|
||||||
|
|
||||||
|
// Human-readable names for each distinct type byte
|
||||||
|
FieldTypeNameDecimal = "DECIMAL"
|
||||||
|
FieldTypeNameTiny = "TINY"
|
||||||
|
FieldTypeNameShort = "SHORT"
|
||||||
|
FieldTypeNameLong = "LONG"
|
||||||
|
FieldTypeNameFloat = "FLOAT"
|
||||||
|
FieldTypeNameDouble = "DOUBLE"
|
||||||
|
FieldTypeNameNULL = "NULL"
|
||||||
|
FieldTypeNameTimestamp = "TIMESTAMP"
|
||||||
|
FieldTypeNameLongLong = "LONGLONG"
|
||||||
|
FieldTypeNameInt24 = "INT24"
|
||||||
|
FieldTypeNameDate = "DATE"
|
||||||
|
FieldTypeNameTime = "TIME"
|
||||||
|
FieldTypeNameDateTime = "DATETIME"
|
||||||
|
FieldTypeNameYear = "YEAR"
|
||||||
|
FieldTypeNameNewDate = "NEWDATE"
|
||||||
|
FieldTypeNameVarChar = "VARCHAR"
|
||||||
|
FieldTypeNameBit = "BIT"
|
||||||
|
FieldTypeNameJSON = "JSON"
|
||||||
|
FieldTypeNameNewDecimal = "NEWDECIMAL"
|
||||||
|
FieldTypeNameEnum = "ENUM"
|
||||||
|
FieldTypeNameSet = "SET"
|
||||||
|
FieldTypeNameTinyBLOB = "TINYBLOB"
|
||||||
|
FieldTypeNameMediumBLOB = "MEDIUMBLOB"
|
||||||
|
FieldTypeNameLongBLOB = "LONGBLOB"
|
||||||
|
FieldTypeNameBLOB = "BLOB"
|
||||||
|
FieldTypeNameVarString = "VARSTRING"
|
||||||
|
FieldTypeNameString = "STRING"
|
||||||
|
FieldTypeNameGeometry = "GEOMETRY"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mapping from each type identifier to human readable string
|
||||||
|
var mysqlTypeMap = map[byte]string{
|
||||||
|
fieldTypeDecimal: FieldTypeNameDecimal,
|
||||||
|
fieldTypeTiny: FieldTypeNameTiny,
|
||||||
|
fieldTypeShort: FieldTypeNameShort,
|
||||||
|
fieldTypeLong: FieldTypeNameLong,
|
||||||
|
fieldTypeFloat: FieldTypeNameFloat,
|
||||||
|
fieldTypeDouble: FieldTypeNameDouble,
|
||||||
|
fieldTypeNULL: FieldTypeNameNULL,
|
||||||
|
fieldTypeTimestamp: FieldTypeNameTimestamp,
|
||||||
|
fieldTypeLongLong: FieldTypeNameLongLong,
|
||||||
|
fieldTypeInt24: FieldTypeNameInt24,
|
||||||
|
fieldTypeDate: FieldTypeNameDate,
|
||||||
|
fieldTypeTime: FieldTypeNameTime,
|
||||||
|
fieldTypeDateTime: FieldTypeNameDateTime,
|
||||||
|
fieldTypeYear: FieldTypeNameYear,
|
||||||
|
fieldTypeNewDate: FieldTypeNameNewDate,
|
||||||
|
fieldTypeVarChar: FieldTypeNameVarChar,
|
||||||
|
fieldTypeBit: FieldTypeNameBit,
|
||||||
|
fieldTypeJSON: FieldTypeNameJSON,
|
||||||
|
fieldTypeNewDecimal: FieldTypeNameNewDecimal,
|
||||||
|
fieldTypeEnum: FieldTypeNameEnum,
|
||||||
|
fieldTypeSet: FieldTypeNameSet,
|
||||||
|
fieldTypeTinyBLOB: FieldTypeNameTinyBLOB,
|
||||||
|
fieldTypeMediumBLOB: FieldTypeNameMediumBLOB,
|
||||||
|
fieldTypeLongBLOB: FieldTypeNameLongBLOB,
|
||||||
|
fieldTypeBLOB: FieldTypeNameBLOB,
|
||||||
|
fieldTypeVarString: FieldTypeNameVarString,
|
||||||
|
fieldTypeString: FieldTypeNameString,
|
||||||
|
fieldTypeGeometry: FieldTypeNameGeometry,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Rows implement the optional RowsColumnTypeDatabaseTypeName interface.
|
||||||
|
// See https://github.com/golang/go/commit/2a85578b0ecd424e95b29d810b7a414a299fd6a7
|
||||||
|
// - (go 1.8 required for this to have any effect)
|
||||||
|
func (rows *mysqlRows) ColumnTypeDatabaseTypeName(index int) string {
|
||||||
|
if typeName, ok := mysqlTypeMap[rows.rs.columns[index].fieldType]; ok {
|
||||||
|
return typeName
|
||||||
|
}
|
||||||
|
return FieldTypeUnknown
|
||||||
|
}
|
||||||
@@ -68,12 +68,6 @@ amdefine@>=0.0.4:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||||
|
|
||||||
ansi-align@^1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba"
|
|
||||||
dependencies:
|
|
||||||
string-width "^1.0.1"
|
|
||||||
|
|
||||||
ansi-escapes@^1.1.0:
|
ansi-escapes@^1.1.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
|
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
|
||||||
@@ -255,7 +249,7 @@ aws4@^1.2.1:
|
|||||||
version "1.5.0"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
|
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
|
||||||
|
|
||||||
babel-code-frame@^6.20.0, babel-code-frame@^6.22.0:
|
babel-code-frame@^6.22.0:
|
||||||
version "6.22.0"
|
version "6.22.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
|
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -499,20 +493,6 @@ boom@2.x.x:
|
|||||||
dependencies:
|
dependencies:
|
||||||
hoek "2.x.x"
|
hoek "2.x.x"
|
||||||
|
|
||||||
boxen@^0.6.0:
|
|
||||||
version "0.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6"
|
|
||||||
dependencies:
|
|
||||||
ansi-align "^1.1.0"
|
|
||||||
camelcase "^2.1.0"
|
|
||||||
chalk "^1.1.1"
|
|
||||||
cli-boxes "^1.0.0"
|
|
||||||
filled-array "^1.0.0"
|
|
||||||
object-assign "^4.0.1"
|
|
||||||
repeating "^2.0.0"
|
|
||||||
string-width "^1.0.1"
|
|
||||||
widest-line "^1.0.0"
|
|
||||||
|
|
||||||
brace-expansion@^1.0.0:
|
brace-expansion@^1.0.0:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
|
||||||
@@ -603,7 +583,7 @@ camelcase@^1.0.2:
|
|||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
|
||||||
|
|
||||||
camelcase@^2.0.0, camelcase@^2.1.0:
|
camelcase@^2.0.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
|
||||||
|
|
||||||
@@ -615,10 +595,6 @@ caniuse-db@^1.0.30000617:
|
|||||||
version "1.0.30000618"
|
version "1.0.30000618"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000618.tgz#821258ff484f662864f28ffbcf849a6247acf1fa"
|
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000618.tgz#821258ff484f662864f28ffbcf849a6247acf1fa"
|
||||||
|
|
||||||
capture-stack-trace@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d"
|
|
||||||
|
|
||||||
caseless@~0.11.0:
|
caseless@~0.11.0:
|
||||||
version "0.11.0"
|
version "0.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
|
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
|
||||||
@@ -697,10 +673,6 @@ clean-css@3.4.x, clean-css@~3.4.2:
|
|||||||
commander "2.8.x"
|
commander "2.8.x"
|
||||||
source-map "0.4.x"
|
source-map "0.4.x"
|
||||||
|
|
||||||
cli-boxes@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
|
|
||||||
|
|
||||||
cli-cursor@^1.0.1:
|
cli-cursor@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
|
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
|
||||||
@@ -823,7 +795,7 @@ concat-map@0.0.1:
|
|||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||||
|
|
||||||
concat-stream@1.5.0:
|
concat-stream@1.5.0, concat-stream@^1.4.1, concat-stream@^1.4.6:
|
||||||
version "1.5.0"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611"
|
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -831,28 +803,6 @@ concat-stream@1.5.0:
|
|||||||
readable-stream "~2.0.0"
|
readable-stream "~2.0.0"
|
||||||
typedarray "~0.0.5"
|
typedarray "~0.0.5"
|
||||||
|
|
||||||
concat-stream@^1.4.1, concat-stream@^1.4.6:
|
|
||||||
version "1.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
|
|
||||||
dependencies:
|
|
||||||
inherits "^2.0.3"
|
|
||||||
readable-stream "^2.2.2"
|
|
||||||
typedarray "^0.0.6"
|
|
||||||
|
|
||||||
configstore@^2.0.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1"
|
|
||||||
dependencies:
|
|
||||||
dot-prop "^3.0.0"
|
|
||||||
graceful-fs "^4.1.2"
|
|
||||||
mkdirp "^0.5.0"
|
|
||||||
object-assign "^4.0.1"
|
|
||||||
os-tmpdir "^1.0.0"
|
|
||||||
osenv "^0.1.0"
|
|
||||||
uuid "^2.0.1"
|
|
||||||
write-file-atomic "^1.1.2"
|
|
||||||
xdg-basedir "^2.0.0"
|
|
||||||
|
|
||||||
connect@^3.3.5:
|
connect@^3.3.5:
|
||||||
version "3.5.0"
|
version "3.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/connect/-/connect-3.5.0.tgz#b357525a0b4c1f50599cd983e1d9efeea9677198"
|
resolved "https://registry.yarnpkg.com/connect/-/connect-3.5.0.tgz#b357525a0b4c1f50599cd983e1d9efeea9677198"
|
||||||
@@ -910,12 +860,6 @@ crc@^3.4.4:
|
|||||||
version "3.4.4"
|
version "3.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b"
|
resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b"
|
||||||
|
|
||||||
create-error-class@^3.0.1:
|
|
||||||
version "3.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
|
|
||||||
dependencies:
|
|
||||||
capture-stack-trace "^1.0.0"
|
|
||||||
|
|
||||||
cross-spawn@^3.0.0:
|
cross-spawn@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
|
||||||
@@ -1062,7 +1006,7 @@ diff@^2.0.2:
|
|||||||
version "2.2.3"
|
version "2.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99"
|
resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99"
|
||||||
|
|
||||||
diff@^3.0.1:
|
diff@^3.2.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
|
resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
|
||||||
|
|
||||||
@@ -1116,18 +1060,6 @@ dot-case@^2.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
no-case "^2.2.0"
|
no-case "^2.2.0"
|
||||||
|
|
||||||
dot-prop@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
|
|
||||||
dependencies:
|
|
||||||
is-obj "^1.0.0"
|
|
||||||
|
|
||||||
duplexer2@^0.1.4:
|
|
||||||
version "0.1.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
|
|
||||||
dependencies:
|
|
||||||
readable-stream "^2.0.2"
|
|
||||||
|
|
||||||
each-async@^0.1.3:
|
each-async@^0.1.3:
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/each-async/-/each-async-0.1.3.tgz#b436025b08da2f86608025519e3096763dedfca3"
|
resolved "https://registry.yarnpkg.com/each-async/-/each-async-0.1.3.tgz#b436025b08da2f86608025519e3096763dedfca3"
|
||||||
@@ -1534,10 +1466,6 @@ fill-range@^2.1.0:
|
|||||||
repeat-element "^1.1.2"
|
repeat-element "^1.1.2"
|
||||||
repeat-string "^1.5.2"
|
repeat-string "^1.5.2"
|
||||||
|
|
||||||
filled-array@^1.0.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/filled-array/-/filled-array-1.1.0.tgz#c3c4f6c663b923459a9aa29912d2d031f1507f84"
|
|
||||||
|
|
||||||
finalhandler@0.5.0:
|
finalhandler@0.5.0:
|
||||||
version "0.5.0"
|
version "0.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7"
|
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7"
|
||||||
@@ -1735,9 +1663,9 @@ glob@7.0.5:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.0"
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
glob@^7.0.0, glob@^7.1.1, glob@~7.1.1:
|
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.0.0:
|
||||||
version "7.1.1"
|
version "7.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a"
|
||||||
dependencies:
|
dependencies:
|
||||||
fs.realpath "^1.0.0"
|
fs.realpath "^1.0.0"
|
||||||
inflight "^1.0.4"
|
inflight "^1.0.4"
|
||||||
@@ -1746,9 +1674,9 @@ glob@^7.0.0, glob@^7.1.1, glob@~7.1.1:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.0"
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
glob@^7.0.3, glob@^7.0.5, glob@~7.0.0:
|
glob@^7.1.1, glob@~7.1.1:
|
||||||
version "7.0.6"
|
version "7.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
|
||||||
dependencies:
|
dependencies:
|
||||||
fs.realpath "^1.0.0"
|
fs.realpath "^1.0.0"
|
||||||
inflight "^1.0.4"
|
inflight "^1.0.4"
|
||||||
@@ -1801,27 +1729,7 @@ gonzales-pe@3.4.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
minimist "1.1.x"
|
minimist "1.1.x"
|
||||||
|
|
||||||
got@^5.0.0:
|
graceful-fs@^4.1.0, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
|
||||||
version "5.7.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
|
|
||||||
dependencies:
|
|
||||||
create-error-class "^3.0.1"
|
|
||||||
duplexer2 "^0.1.4"
|
|
||||||
is-redirect "^1.0.0"
|
|
||||||
is-retry-allowed "^1.0.0"
|
|
||||||
is-stream "^1.0.0"
|
|
||||||
lowercase-keys "^1.0.0"
|
|
||||||
node-status-codes "^1.0.0"
|
|
||||||
object-assign "^4.0.1"
|
|
||||||
parse-json "^2.1.0"
|
|
||||||
pinkie-promise "^2.0.0"
|
|
||||||
read-all-stream "^3.0.0"
|
|
||||||
readable-stream "^2.0.5"
|
|
||||||
timed-out "^3.0.0"
|
|
||||||
unzip-response "^1.0.2"
|
|
||||||
url-parse-lax "^1.0.0"
|
|
||||||
|
|
||||||
graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
|
|
||||||
version "4.1.11"
|
version "4.1.11"
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||||
|
|
||||||
@@ -2311,7 +2219,7 @@ inherits@1:
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
|
||||||
|
|
||||||
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
|
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||||
|
|
||||||
@@ -2430,10 +2338,6 @@ is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4:
|
|||||||
jsonpointer "^4.0.0"
|
jsonpointer "^4.0.0"
|
||||||
xtend "^4.0.0"
|
xtend "^4.0.0"
|
||||||
|
|
||||||
is-npm@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
|
|
||||||
|
|
||||||
is-number@^0.1.1:
|
is-number@^0.1.1:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806"
|
resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806"
|
||||||
@@ -2444,10 +2348,6 @@ is-number@^2.0.2, is-number@^2.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
kind-of "^3.0.2"
|
kind-of "^3.0.2"
|
||||||
|
|
||||||
is-obj@^1.0.0:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
|
|
||||||
|
|
||||||
is-path-cwd@^1.0.0:
|
is-path-cwd@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
|
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
|
||||||
@@ -2476,21 +2376,13 @@ is-property@^1.0.0:
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
|
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
|
||||||
|
|
||||||
is-redirect@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
|
|
||||||
|
|
||||||
is-resolvable@^1.0.0:
|
is-resolvable@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
|
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
|
||||||
dependencies:
|
dependencies:
|
||||||
tryit "^1.0.1"
|
tryit "^1.0.1"
|
||||||
|
|
||||||
is-retry-allowed@^1.0.0:
|
is-stream@^1.0.1:
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
|
|
||||||
|
|
||||||
is-stream@^1.0.0, is-stream@^1.0.1:
|
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||||
|
|
||||||
@@ -2811,20 +2703,10 @@ klaw@^1.0.0:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs "^4.1.9"
|
graceful-fs "^4.1.9"
|
||||||
|
|
||||||
latest-version@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-2.0.0.tgz#56f8d6139620847b8017f8f1f4d78e211324168b"
|
|
||||||
dependencies:
|
|
||||||
package-json "^2.0.0"
|
|
||||||
|
|
||||||
lazy-cache@^1.0.3:
|
lazy-cache@^1.0.3:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
|
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
|
||||||
|
|
||||||
lazy-req@^1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
|
|
||||||
|
|
||||||
lazystream@^1.0.0:
|
lazystream@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
|
resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
|
||||||
@@ -3006,10 +2888,6 @@ lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2:
|
|||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.3.tgz#c92393d976793eee5ba4edb583cf8eae35bd9bfb"
|
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.3.tgz#c92393d976793eee5ba4edb583cf8eae35bd9bfb"
|
||||||
|
|
||||||
lowercase-keys@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306"
|
|
||||||
|
|
||||||
lru-cache@2:
|
lru-cache@2:
|
||||||
version "2.7.3"
|
version "2.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
|
||||||
@@ -3294,10 +3172,6 @@ node-sass@^3.7.0:
|
|||||||
request "^2.61.0"
|
request "^2.61.0"
|
||||||
sass-graph "^2.1.1"
|
sass-graph "^2.1.1"
|
||||||
|
|
||||||
node-status-codes@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"
|
|
||||||
|
|
||||||
"nomnom@>= 1.5.x":
|
"nomnom@>= 1.5.x":
|
||||||
version "1.8.1"
|
version "1.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
|
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
|
||||||
@@ -3442,22 +3316,13 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1:
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||||
|
|
||||||
osenv@0, osenv@^0.1.0:
|
osenv@0:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
|
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
|
||||||
dependencies:
|
dependencies:
|
||||||
os-homedir "^1.0.0"
|
os-homedir "^1.0.0"
|
||||||
os-tmpdir "^1.0.0"
|
os-tmpdir "^1.0.0"
|
||||||
|
|
||||||
package-json@^2.0.0:
|
|
||||||
version "2.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/package-json/-/package-json-2.4.0.tgz#0d15bd67d1cbbddbb2ca222ff2edb86bcb31a8bb"
|
|
||||||
dependencies:
|
|
||||||
got "^5.0.0"
|
|
||||||
registry-auth-token "^3.0.1"
|
|
||||||
registry-url "^3.0.3"
|
|
||||||
semver "^5.1.0"
|
|
||||||
|
|
||||||
pako@~0.2.0:
|
pako@~0.2.0:
|
||||||
version "0.2.9"
|
version "0.2.9"
|
||||||
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
|
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
|
||||||
@@ -3477,7 +3342,7 @@ parse-glob@^3.0.4:
|
|||||||
is-extglob "^1.0.0"
|
is-extglob "^1.0.0"
|
||||||
is-glob "^2.0.0"
|
is-glob "^2.0.0"
|
||||||
|
|
||||||
parse-json@^2.1.0, parse-json@^2.2.0:
|
parse-json@^2.2.0:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
|
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3536,6 +3401,10 @@ path-is-inside@^1.0.1:
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
|
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
|
||||||
|
|
||||||
|
path-parse@^1.0.5:
|
||||||
|
version "1.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
|
||||||
|
|
||||||
path-type@^1.0.0:
|
path-type@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||||
@@ -3621,10 +3490,6 @@ prelude-ls@~1.1.2:
|
|||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||||
|
|
||||||
prepend-http@^1.0.1:
|
|
||||||
version "1.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
|
||||||
|
|
||||||
preserve@^0.2.0:
|
preserve@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||||
@@ -3723,7 +3588,7 @@ raw-body@~2.2.0:
|
|||||||
iconv-lite "0.4.15"
|
iconv-lite "0.4.15"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
rc@^1.0.1, rc@^1.1.6, rc@~1.1.6:
|
rc@~1.1.6:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9"
|
resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3732,13 +3597,6 @@ rc@^1.0.1, rc@^1.1.6, rc@~1.1.6:
|
|||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
strip-json-comments "~1.0.4"
|
strip-json-comments "~1.0.4"
|
||||||
|
|
||||||
read-all-stream@^3.0.0:
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
|
|
||||||
dependencies:
|
|
||||||
pinkie-promise "^2.0.0"
|
|
||||||
readable-stream "^2.0.0"
|
|
||||||
|
|
||||||
read-pkg-up@^1.0.1:
|
read-pkg-up@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
|
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
|
||||||
@@ -3769,7 +3627,7 @@ readable-stream@1.1:
|
|||||||
isarray "0.0.1"
|
isarray "0.0.1"
|
||||||
string_decoder "~0.10.x"
|
string_decoder "~0.10.x"
|
||||||
|
|
||||||
readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.2.2:
|
readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5:
|
||||||
version "2.2.2"
|
version "2.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3852,18 +3710,6 @@ regex-cache@^0.4.2:
|
|||||||
is-equal-shallow "^0.1.3"
|
is-equal-shallow "^0.1.3"
|
||||||
is-primitive "^2.0.0"
|
is-primitive "^2.0.0"
|
||||||
|
|
||||||
registry-auth-token@^3.0.1:
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.1.0.tgz#997c08256e0c7999837b90e944db39d8a790276b"
|
|
||||||
dependencies:
|
|
||||||
rc "^1.1.6"
|
|
||||||
|
|
||||||
registry-url@^3.0.3:
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
|
|
||||||
dependencies:
|
|
||||||
rc "^1.0.1"
|
|
||||||
|
|
||||||
relateurl@0.2.x:
|
relateurl@0.2.x:
|
||||||
version "0.2.7"
|
version "0.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
||||||
@@ -3961,10 +3807,16 @@ resolve-pkg@^0.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
resolve-from "^2.0.0"
|
resolve-from "^2.0.0"
|
||||||
|
|
||||||
resolve@1.1.x, resolve@^1.1.6, resolve@^1.1.7, resolve@~1.1.0:
|
resolve@1.1.x, resolve@^1.1.6, resolve@~1.1.0:
|
||||||
version "1.1.7"
|
version "1.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
||||||
|
|
||||||
|
resolve@^1.3.2:
|
||||||
|
version "1.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5"
|
||||||
|
dependencies:
|
||||||
|
path-parse "^1.0.5"
|
||||||
|
|
||||||
restore-cursor@^1.0.1:
|
restore-cursor@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
|
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
|
||||||
@@ -4048,13 +3900,7 @@ sass-lint@^1.10.2:
|
|||||||
path-is-absolute "^1.0.0"
|
path-is-absolute "^1.0.0"
|
||||||
util "^0.10.3"
|
util "^0.10.3"
|
||||||
|
|
||||||
semver-diff@^2.0.0:
|
"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@~5.3.0:
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
|
|
||||||
dependencies:
|
|
||||||
semver "^5.0.3"
|
|
||||||
|
|
||||||
"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@~5.3.0:
|
|
||||||
version "5.3.0"
|
version "5.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
||||||
|
|
||||||
@@ -4122,10 +3968,6 @@ slice-ansi@0.0.4:
|
|||||||
version "0.0.4"
|
version "0.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
||||||
|
|
||||||
slide@^1.1.5:
|
|
||||||
version "1.1.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
|
|
||||||
|
|
||||||
snake-case@^2.1.0:
|
snake-case@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
|
resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
|
||||||
@@ -4468,10 +4310,6 @@ through@^2.3.6:
|
|||||||
version "2.3.8"
|
version "2.3.8"
|
||||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||||
|
|
||||||
timed-out@^3.0.0:
|
|
||||||
version "3.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217"
|
|
||||||
|
|
||||||
tiny-emitter@^1.0.0:
|
tiny-emitter@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.1.0.tgz#ab405a21ffed814a76c19739648093d70654fecb"
|
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.1.0.tgz#ab405a21ffed814a76c19739648093d70654fecb"
|
||||||
@@ -4544,18 +4382,23 @@ tryor@~0.1.2:
|
|||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b"
|
resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b"
|
||||||
|
|
||||||
tslint@^4.0.2:
|
tslint@^5.1.0:
|
||||||
version "4.4.2"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-4.4.2.tgz#b14cb79ae039c72471ab4c2627226b940dda19c6"
|
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.1.0.tgz#51a47baeeb58956fcd617bd2cf00e2ef0eea2ed9"
|
||||||
dependencies:
|
dependencies:
|
||||||
babel-code-frame "^6.20.0"
|
babel-code-frame "^6.22.0"
|
||||||
colors "^1.1.2"
|
colors "^1.1.2"
|
||||||
diff "^3.0.1"
|
diff "^3.2.0"
|
||||||
findup-sync "~0.3.0"
|
findup-sync "~0.3.0"
|
||||||
glob "^7.1.1"
|
glob "^7.1.1"
|
||||||
optimist "~0.6.0"
|
optimist "~0.6.0"
|
||||||
resolve "^1.1.7"
|
resolve "^1.3.2"
|
||||||
update-notifier "^1.0.2"
|
semver "^5.3.0"
|
||||||
|
tsutils "^1.4.0"
|
||||||
|
|
||||||
|
tsutils@^1.4.0:
|
||||||
|
version "1.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.7.0.tgz#2e63ccc2d6912bb095f7e363ff4100721dc86f50"
|
||||||
|
|
||||||
tunnel-agent@~0.4.1:
|
tunnel-agent@~0.4.1:
|
||||||
version "0.4.3"
|
version "0.4.3"
|
||||||
@@ -4578,13 +4421,13 @@ type-is@~1.6.10, type-is@~1.6.14:
|
|||||||
media-typer "0.3.0"
|
media-typer "0.3.0"
|
||||||
mime-types "~2.1.13"
|
mime-types "~2.1.13"
|
||||||
|
|
||||||
typedarray@^0.0.6, typedarray@~0.0.5:
|
typedarray@~0.0.5:
|
||||||
version "0.0.6"
|
version "0.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
|
|
||||||
typescript@^2.1.4:
|
typescript@^2.2.2:
|
||||||
version "2.1.5"
|
version "2.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.5.tgz#6fe9479e00e01855247cea216e7561bafcdbcd4a"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.2.tgz#606022508479b55ffa368b58fee963a03dfd7b0c"
|
||||||
|
|
||||||
uglify-js@2.6.x:
|
uglify-js@2.6.x:
|
||||||
version "2.6.4"
|
version "2.6.4"
|
||||||
@@ -4640,23 +4483,6 @@ unpipe@1.0.0, unpipe@~1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||||
|
|
||||||
unzip-response@^1.0.2:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
|
|
||||||
|
|
||||||
update-notifier@^1.0.2:
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-1.0.3.tgz#8f92c515482bd6831b7c93013e70f87552c7cf5a"
|
|
||||||
dependencies:
|
|
||||||
boxen "^0.6.0"
|
|
||||||
chalk "^1.0.0"
|
|
||||||
configstore "^2.0.0"
|
|
||||||
is-npm "^1.0.0"
|
|
||||||
latest-version "^2.0.0"
|
|
||||||
lazy-req "^1.1.0"
|
|
||||||
semver-diff "^2.0.0"
|
|
||||||
xdg-basedir "^2.0.0"
|
|
||||||
|
|
||||||
upper-case-first@^1.1.0, upper-case-first@^1.1.2:
|
upper-case-first@^1.1.0, upper-case-first@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115"
|
resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115"
|
||||||
@@ -4671,12 +4497,6 @@ uri-path@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/uri-path/-/uri-path-1.0.0.tgz#9747f018358933c31de0fccfd82d138e67262e32"
|
resolved "https://registry.yarnpkg.com/uri-path/-/uri-path-1.0.0.tgz#9747f018358933c31de0fccfd82d138e67262e32"
|
||||||
|
|
||||||
url-parse-lax@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
|
|
||||||
dependencies:
|
|
||||||
prepend-http "^1.0.1"
|
|
||||||
|
|
||||||
user-home@^2.0.0:
|
user-home@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
|
resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
|
||||||
@@ -4718,7 +4538,7 @@ utils-merge@1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
|
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
|
||||||
|
|
||||||
uuid@^2.0.1, uuid@^2.0.2:
|
uuid@^2.0.2:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
|
||||||
|
|
||||||
@@ -4809,12 +4629,6 @@ wide-align@^1.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
string-width "^1.0.1"
|
string-width "^1.0.1"
|
||||||
|
|
||||||
widest-line@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c"
|
|
||||||
dependencies:
|
|
||||||
string-width "^1.0.1"
|
|
||||||
|
|
||||||
window-size@0.1.0:
|
window-size@0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
|
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
|
||||||
@@ -4858,14 +4672,6 @@ wrappy@1:
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||||
|
|
||||||
write-file-atomic@^1.1.2:
|
|
||||||
version "1.3.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a"
|
|
||||||
dependencies:
|
|
||||||
graceful-fs "^4.1.11"
|
|
||||||
imurmurhash "^0.1.4"
|
|
||||||
slide "^1.1.5"
|
|
||||||
|
|
||||||
write@^0.2.1:
|
write@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
|
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
|
||||||
@@ -4879,12 +4685,6 @@ ws@1.0.1:
|
|||||||
options ">=0.0.5"
|
options ">=0.0.5"
|
||||||
ultron "1.0.x"
|
ultron "1.0.x"
|
||||||
|
|
||||||
xdg-basedir@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2"
|
|
||||||
dependencies:
|
|
||||||
os-homedir "^1.0.0"
|
|
||||||
|
|
||||||
xml-char-classes@^1.0.0:
|
xml-char-classes@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d"
|
resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d"
|
||||||
|
|||||||
Reference in New Issue
Block a user