Merge branch 'master' into flux-staging
commit
8372859dee
|
@ -57,31 +57,31 @@ func init() {
|
|||
RunE: authorizationCreateF,
|
||||
}
|
||||
|
||||
authorizationCreateCmd.Flags().StringVarP(&authorizationCreateFlags.org, "org", "o", "", "org name (required)")
|
||||
authorizationCreateCmd.Flags().StringVarP(&authorizationCreateFlags.org, "org", "o", "", "The organization name (required)")
|
||||
authorizationCreateCmd.MarkFlagRequired("org")
|
||||
|
||||
authorizationCreateCmd.Flags().StringVarP(&authorizationCreateFlags.user, "user", "u", "", "user name")
|
||||
authorizationCreateCmd.Flags().StringVarP(&authorizationCreateFlags.user, "user", "u", "", "The user name")
|
||||
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeUserPermission, "write-user", "", false, "grants the permission to perform mutative actions against organization users")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readUserPermission, "read-user", "", false, "grants the permission to perform read actions against organization users")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeUserPermission, "write-user", "", false, "Grants the permission to perform mutative actions against organization users")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readUserPermission, "read-user", "", false, "Grants the permission to perform read actions against organization users")
|
||||
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeBucketsPermission, "write-buckets", "", false, "grants the permission to perform mutative actions against organization buckets")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readBucketsPermission, "read-buckets", "", false, "grants the permission to perform read actions against organization buckets")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeBucketsPermission, "write-buckets", "", false, "Grants the permission to perform mutative actions against organization buckets")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readBucketsPermission, "read-buckets", "", false, "Grants the permission to perform read actions against organization buckets")
|
||||
|
||||
authorizationCreateCmd.Flags().StringArrayVarP(&authorizationCreateFlags.writeBucketPermissions, "write-bucket", "", []string{}, "bucket id")
|
||||
authorizationCreateCmd.Flags().StringArrayVarP(&authorizationCreateFlags.readBucketPermissions, "read-bucket", "", []string{}, "bucket id")
|
||||
authorizationCreateCmd.Flags().StringArrayVarP(&authorizationCreateFlags.writeBucketPermissions, "write-bucket", "", []string{}, "The bucket id")
|
||||
authorizationCreateCmd.Flags().StringArrayVarP(&authorizationCreateFlags.readBucketPermissions, "read-bucket", "", []string{}, "The bucket id")
|
||||
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeTasksPermission, "write-tasks", "", false, "grants the permission to create tasks")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readTasksPermission, "read-tasks", "", false, "grants the permission to read tasks")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeTasksPermission, "write-tasks", "", false, "Grants the permission to create tasks")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readTasksPermission, "read-tasks", "", false, "Grants the permission to read tasks")
|
||||
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeTelegrafsPermission, "write-telegrafs", "", false, "grants the permission to create telegraf configs")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readTelegrafsPermission, "read-telegrafs", "", false, "grants the permission to read telegraf configs")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeTelegrafsPermission, "write-telegrafs", "", false, "Grants the permission to create telegraf configs")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readTelegrafsPermission, "read-telegrafs", "", false, "Grants the permission to read telegraf configs")
|
||||
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeOrganizationsPermission, "write-orgs", "", false, "grants the permission to create organizations")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readOrganizationsPermission, "read-orgs", "", false, "grants the permission to read organizations")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeOrganizationsPermission, "write-orgs", "", false, "Grants the permission to create organizations")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readOrganizationsPermission, "read-orgs", "", false, "Grants the permission to read organizations")
|
||||
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeDashboardsPermission, "write-dashboards", "", false, "grants the permission to create dashboards")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readDashboardsPermission, "read-dashboards", "", false, "grants the permission to read dashboards")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.writeDashboardsPermission, "write-dashboards", "", false, "Grants the permission to create dashboards")
|
||||
authorizationCreateCmd.Flags().BoolVarP(&authorizationCreateFlags.readDashboardsPermission, "read-dashboards", "", false, "Grants the permission to read dashboards")
|
||||
|
||||
authorizationCmd.AddCommand(authorizationCreateCmd)
|
||||
}
|
||||
|
@ -297,9 +297,9 @@ func init() {
|
|||
RunE: authorizationFindF,
|
||||
}
|
||||
|
||||
authorizationFindCmd.Flags().StringVarP(&authorizationFindFlags.user, "user", "u", "", "user")
|
||||
authorizationFindCmd.Flags().StringVarP(&authorizationFindFlags.userID, "user-id", "", "", "user ID")
|
||||
authorizationFindCmd.Flags().StringVarP(&authorizationFindFlags.id, "id", "i", "", "authorization ID")
|
||||
authorizationFindCmd.Flags().StringVarP(&authorizationFindFlags.user, "user", "u", "", "The user")
|
||||
authorizationFindCmd.Flags().StringVarP(&authorizationFindFlags.userID, "user-id", "", "", "The user ID")
|
||||
authorizationFindCmd.Flags().StringVarP(&authorizationFindFlags.id, "id", "i", "", "The authorization ID")
|
||||
|
||||
authorizationCmd.AddCommand(authorizationFindCmd)
|
||||
}
|
||||
|
@ -398,7 +398,7 @@ func init() {
|
|||
RunE: authorizationDeleteF,
|
||||
}
|
||||
|
||||
authorizationDeleteCmd.Flags().StringVarP(&authorizationDeleteFlags.id, "id", "i", "", "authorization id (required)")
|
||||
authorizationDeleteCmd.Flags().StringVarP(&authorizationDeleteFlags.id, "id", "i", "", "The authorization ID (required)")
|
||||
authorizationDeleteCmd.MarkFlagRequired("id")
|
||||
|
||||
authorizationCmd.AddCommand(authorizationDeleteCmd)
|
||||
|
@ -463,11 +463,11 @@ var authorizationActiveFlags AuthorizationActiveFlags
|
|||
func init() {
|
||||
authorizationActiveCmd := &cobra.Command{
|
||||
Use: "active",
|
||||
Short: "active authorization",
|
||||
Short: "Active authorization",
|
||||
RunE: authorizationActiveF,
|
||||
}
|
||||
|
||||
authorizationActiveCmd.Flags().StringVarP(&authorizationActiveFlags.id, "id", "i", "", "authorization id (required)")
|
||||
authorizationActiveCmd.Flags().StringVarP(&authorizationActiveFlags.id, "id", "i", "", "The authorization ID (required)")
|
||||
authorizationActiveCmd.MarkFlagRequired("id")
|
||||
|
||||
authorizationCmd.AddCommand(authorizationActiveCmd)
|
||||
|
@ -532,11 +532,11 @@ var authorizationInactiveFlags AuthorizationInactiveFlags
|
|||
func init() {
|
||||
authorizationInactiveCmd := &cobra.Command{
|
||||
Use: "inactive",
|
||||
Short: "inactive authorization",
|
||||
Short: "Inactive authorization",
|
||||
RunE: authorizationInactiveF,
|
||||
}
|
||||
|
||||
authorizationInactiveCmd.Flags().StringVarP(&authorizationInactiveFlags.id, "id", "i", "", "authorization id (required)")
|
||||
authorizationInactiveCmd.Flags().StringVarP(&authorizationInactiveFlags.id, "id", "i", "", "The authorization ID (required)")
|
||||
authorizationInactiveCmd.MarkFlagRequired("id")
|
||||
|
||||
authorizationCmd.AddCommand(authorizationInactiveCmd)
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
// Bucket Command
|
||||
var bucketCmd = &cobra.Command{
|
||||
Use: "bucket",
|
||||
Short: "bucket related commands",
|
||||
Short: "Bucket management commands",
|
||||
Run: bucketF,
|
||||
}
|
||||
|
||||
|
@ -42,10 +42,10 @@ func init() {
|
|||
Run: bucketCreateF,
|
||||
}
|
||||
|
||||
bucketCreateCmd.Flags().StringVarP(&bucketCreateFlags.name, "name", "n", "", "name of bucket that will be created")
|
||||
bucketCreateCmd.Flags().DurationVarP(&bucketCreateFlags.retention, "retention", "r", 0, "duration in nanoseconds data will live in bucket")
|
||||
bucketCreateCmd.Flags().StringVarP(&bucketCreateFlags.org, "org", "o", "", "name of the organization that owns the bucket")
|
||||
bucketCreateCmd.Flags().StringVarP(&bucketCreateFlags.orgID, "org-id", "", "", "id of the organization that owns the bucket")
|
||||
bucketCreateCmd.Flags().StringVarP(&bucketCreateFlags.name, "name", "n", "", "Name of bucket that will be created")
|
||||
bucketCreateCmd.Flags().DurationVarP(&bucketCreateFlags.retention, "retention", "r", 0, "Duration in nanoseconds data will live in bucket")
|
||||
bucketCreateCmd.Flags().StringVarP(&bucketCreateFlags.org, "org", "o", "", "Name of the organization that owns the bucket")
|
||||
bucketCreateCmd.Flags().StringVarP(&bucketCreateFlags.orgID, "org-id", "", "", "The ID of the organization that owns the bucket")
|
||||
bucketCreateCmd.MarkFlagRequired("name")
|
||||
|
||||
bucketCmd.AddCommand(bucketCreateCmd)
|
||||
|
@ -143,10 +143,10 @@ func init() {
|
|||
Run: bucketFindF,
|
||||
}
|
||||
|
||||
bucketFindCmd.Flags().StringVarP(&bucketFindFlags.name, "name", "n", "", "bucket name")
|
||||
bucketFindCmd.Flags().StringVarP(&bucketFindFlags.id, "id", "i", "", "bucket ID")
|
||||
bucketFindCmd.Flags().StringVarP(&bucketFindFlags.orgID, "org-id", "", "", "bucket organization ID")
|
||||
bucketFindCmd.Flags().StringVarP(&bucketFindFlags.org, "org", "o", "", "bucket organization name")
|
||||
bucketFindCmd.Flags().StringVarP(&bucketFindFlags.name, "name", "n", "", "The bucket name")
|
||||
bucketFindCmd.Flags().StringVarP(&bucketFindFlags.id, "id", "i", "", "The bucket ID")
|
||||
bucketFindCmd.Flags().StringVarP(&bucketFindFlags.orgID, "org-id", "", "", "The bucket organization ID")
|
||||
bucketFindCmd.Flags().StringVarP(&bucketFindFlags.org, "org", "o", "", "The bucket organization name")
|
||||
|
||||
bucketCmd.AddCommand(bucketFindCmd)
|
||||
}
|
||||
|
@ -233,9 +233,9 @@ func init() {
|
|||
Run: bucketUpdateF,
|
||||
}
|
||||
|
||||
bucketUpdateCmd.Flags().StringVarP(&bucketUpdateFlags.id, "id", "i", "", "bucket ID (required)")
|
||||
bucketUpdateCmd.Flags().StringVarP(&bucketUpdateFlags.name, "name", "n", "", "new bucket name")
|
||||
bucketUpdateCmd.Flags().DurationVarP(&bucketUpdateFlags.retention, "retention", "r", 0, "new duration data will live in bucket")
|
||||
bucketUpdateCmd.Flags().StringVarP(&bucketUpdateFlags.id, "id", "i", "", "The bucket ID (required)")
|
||||
bucketUpdateCmd.Flags().StringVarP(&bucketUpdateFlags.name, "name", "n", "", "New bucket name")
|
||||
bucketUpdateCmd.Flags().DurationVarP(&bucketUpdateFlags.retention, "retention", "r", 0, "New duration data will live in bucket")
|
||||
bucketUpdateCmd.MarkFlagRequired("id")
|
||||
|
||||
bucketCmd.AddCommand(bucketUpdateCmd)
|
||||
|
@ -345,7 +345,7 @@ func init() {
|
|||
Run: bucketDeleteF,
|
||||
}
|
||||
|
||||
bucketDeleteCmd.Flags().StringVarP(&bucketDeleteFlags.id, "id", "i", "", "bucket id (required)")
|
||||
bucketDeleteCmd.Flags().StringVarP(&bucketDeleteFlags.id, "id", "i", "", "The bucket ID (required)")
|
||||
bucketDeleteCmd.MarkFlagRequired("id")
|
||||
|
||||
bucketCmd.AddCommand(bucketDeleteCmd)
|
||||
|
|
|
@ -80,12 +80,25 @@ func init() {
|
|||
}
|
||||
|
||||
influxCmd.PersistentFlags().BoolVar(&flags.local, "local", false, "Run commands locally against the filesystem")
|
||||
|
||||
// Override help on all the commands tree
|
||||
walk(influxCmd, func(c *cobra.Command) {
|
||||
c.Flags().BoolP("help", "h", false, fmt.Sprintf("Help for the %s command ", c.Name()))
|
||||
})
|
||||
}
|
||||
|
||||
func influxF(cmd *cobra.Command, args []string) {
|
||||
cmd.Usage()
|
||||
}
|
||||
|
||||
// walk calls f for c and all of its children.
|
||||
func walk(c *cobra.Command, f func(*cobra.Command)) {
|
||||
f(c)
|
||||
for _, c := range c.Commands() {
|
||||
walk(c, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the influx command
|
||||
func Execute() {
|
||||
if err := influxCmd.Execute(); err != nil {
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
var organizationCmd = &cobra.Command{
|
||||
Use: "org",
|
||||
Aliases: []string{"organization"},
|
||||
Short: "Organization related commands",
|
||||
Short: "Organization management commands",
|
||||
Run: organizationF,
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ func init() {
|
|||
Run: organizationCreateF,
|
||||
}
|
||||
|
||||
organizationCreateCmd.Flags().StringVarP(&organizationCreateFlags.name, "name", "n", "", "name of organization that will be created")
|
||||
organizationCreateCmd.Flags().StringVarP(&organizationCreateFlags.name, "name", "n", "", "The name of organization that will be created")
|
||||
organizationCreateCmd.MarkFlagRequired("name")
|
||||
|
||||
organizationCmd.AddCommand(organizationCreateCmd)
|
||||
|
@ -109,8 +109,8 @@ func init() {
|
|||
Run: organizationFindF,
|
||||
}
|
||||
|
||||
organizationFindCmd.Flags().StringVarP(&organizationFindFlags.name, "name", "n", "", "organization name")
|
||||
organizationFindCmd.Flags().StringVarP(&organizationFindFlags.id, "id", "i", "", "organization id")
|
||||
organizationFindCmd.Flags().StringVarP(&organizationFindFlags.name, "name", "n", "", "The organization name")
|
||||
organizationFindCmd.Flags().StringVarP(&organizationFindFlags.id, "id", "i", "", "The organization ID")
|
||||
|
||||
organizationCmd.AddCommand(organizationFindCmd)
|
||||
}
|
||||
|
@ -171,8 +171,8 @@ func init() {
|
|||
Run: organizationUpdateF,
|
||||
}
|
||||
|
||||
organizationUpdateCmd.Flags().StringVarP(&organizationUpdateFlags.id, "id", "i", "", "organization ID (required)")
|
||||
organizationUpdateCmd.Flags().StringVarP(&organizationUpdateFlags.name, "name", "n", "", "organization name")
|
||||
organizationUpdateCmd.Flags().StringVarP(&organizationUpdateFlags.id, "id", "i", "", "The organization ID (required)")
|
||||
organizationUpdateCmd.Flags().StringVarP(&organizationUpdateFlags.name, "name", "n", "", "The organization name")
|
||||
organizationUpdateCmd.MarkFlagRequired("id")
|
||||
|
||||
organizationCmd.AddCommand(organizationUpdateCmd)
|
||||
|
@ -214,7 +214,7 @@ func organizationUpdateF(cmd *cobra.Command, args []string) {
|
|||
w.Flush()
|
||||
}
|
||||
|
||||
// Delete command
|
||||
// OrganizationDeleteFlags contains the flag of the org delete command
|
||||
type OrganizationDeleteFlags struct {
|
||||
id string
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ func init() {
|
|||
Run: organizationDeleteF,
|
||||
}
|
||||
|
||||
organizationDeleteCmd.Flags().StringVarP(&organizationDeleteFlags.id, "id", "i", "", "organization id (required)")
|
||||
organizationDeleteCmd.Flags().StringVarP(&organizationDeleteFlags.id, "id", "i", "", "The organization ID (required)")
|
||||
organizationDeleteCmd.MarkFlagRequired("id")
|
||||
|
||||
organizationCmd.AddCommand(organizationDeleteCmd)
|
||||
|
@ -276,7 +276,7 @@ func init() {
|
|||
// Member management
|
||||
var organizationMembersCmd = &cobra.Command{
|
||||
Use: "members",
|
||||
Short: "organization membership commands",
|
||||
Short: "Organization membership commands",
|
||||
Run: organizationF,
|
||||
}
|
||||
|
||||
|
@ -363,8 +363,8 @@ func init() {
|
|||
Run: organizationMembersListF,
|
||||
}
|
||||
|
||||
organizationMembersListCmd.Flags().StringVarP(&organizationMembersListFlags.id, "id", "i", "", "organization id")
|
||||
organizationMembersListCmd.Flags().StringVarP(&organizationMembersListFlags.name, "name", "n", "", "organization name")
|
||||
organizationMembersListCmd.Flags().StringVarP(&organizationMembersListFlags.id, "id", "i", "", "The organization ID")
|
||||
organizationMembersListCmd.Flags().StringVarP(&organizationMembersListFlags.name, "name", "n", "", "The organization name")
|
||||
|
||||
organizationMembersCmd.AddCommand(organizationMembersListCmd)
|
||||
}
|
||||
|
@ -450,9 +450,9 @@ func init() {
|
|||
Run: organizationMembersAddF,
|
||||
}
|
||||
|
||||
organizationMembersAddCmd.Flags().StringVarP(&organizationMembersAddFlags.id, "id", "i", "", "organization id")
|
||||
organizationMembersAddCmd.Flags().StringVarP(&organizationMembersAddFlags.name, "name", "n", "", "organization name")
|
||||
organizationMembersAddCmd.Flags().StringVarP(&organizationMembersAddFlags.memberId, "member", "o", "", "member id")
|
||||
organizationMembersAddCmd.Flags().StringVarP(&organizationMembersAddFlags.id, "id", "i", "", "The organization ID")
|
||||
organizationMembersAddCmd.Flags().StringVarP(&organizationMembersAddFlags.name, "name", "n", "", "The organization name")
|
||||
organizationMembersAddCmd.Flags().StringVarP(&organizationMembersAddFlags.memberId, "member", "o", "", "The member ID")
|
||||
organizationMembersAddCmd.MarkFlagRequired("member")
|
||||
|
||||
organizationMembersCmd.AddCommand(organizationMembersAddCmd)
|
||||
|
@ -533,9 +533,9 @@ func init() {
|
|||
Run: organizationMembersRemoveF,
|
||||
}
|
||||
|
||||
organizationMembersRemoveCmd.Flags().StringVarP(&organizationMembersRemoveFlags.id, "id", "i", "", "organization id")
|
||||
organizationMembersRemoveCmd.Flags().StringVarP(&organizationMembersRemoveFlags.name, "name", "n", "", "organization name")
|
||||
organizationMembersRemoveCmd.Flags().StringVarP(&organizationMembersRemoveFlags.memberId, "member", "o", "", "member id")
|
||||
organizationMembersRemoveCmd.Flags().StringVarP(&organizationMembersRemoveFlags.id, "id", "i", "", "The organization ID")
|
||||
organizationMembersRemoveCmd.Flags().StringVarP(&organizationMembersRemoveFlags.name, "name", "n", "", "The organization name")
|
||||
organizationMembersRemoveCmd.Flags().StringVarP(&organizationMembersRemoveFlags.memberId, "member", "o", "", "The member ID")
|
||||
organizationMembersRemoveCmd.MarkFlagRequired("member")
|
||||
|
||||
organizationMembersCmd.AddCommand(organizationMembersRemoveCmd)
|
||||
|
|
|
@ -13,9 +13,9 @@ import (
|
|||
|
||||
var queryCmd = &cobra.Command{
|
||||
Use: "query [query literal or @/path/to/query.flux]",
|
||||
Short: "Execute an Flux query",
|
||||
Short: "Execute a Flux query",
|
||||
Long: `Execute a literal Flux query provided as a string,
|
||||
or execute a literal Flux query contained in a file by specifying the file prefixed with an @ sign.`,
|
||||
or execute a literal Flux query contained in a file by specifying the file prefixed with an @ sign.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: fluxQueryF,
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ var queryFlags struct {
|
|||
}
|
||||
|
||||
func init() {
|
||||
queryCmd.PersistentFlags().StringVar(&queryFlags.OrgID, "org-id", "", "Organization ID")
|
||||
queryCmd.PersistentFlags().StringVar(&queryFlags.OrgID, "org-id", "", "The organization ID")
|
||||
viper.BindEnv("ORG_ID")
|
||||
if h := viper.GetString("ORG_ID"); h != "" {
|
||||
queryFlags.OrgID = h
|
||||
|
|
|
@ -27,13 +27,13 @@ var replFlags struct {
|
|||
}
|
||||
|
||||
func init() {
|
||||
replCmd.PersistentFlags().StringVar(&replFlags.OrgID, "org-id", "", "ID of organization to query")
|
||||
replCmd.PersistentFlags().StringVar(&replFlags.OrgID, "org-id", "", "The ID of organization to query")
|
||||
viper.BindEnv("ORG_ID")
|
||||
if h := viper.GetString("ORG_ID"); h != "" {
|
||||
replFlags.OrgID = h
|
||||
}
|
||||
|
||||
replCmd.PersistentFlags().StringVarP(&replFlags.Org, "org", "o", "", "name of the organization")
|
||||
replCmd.PersistentFlags().StringVarP(&replFlags.Org, "org", "o", "", "The name of the organization")
|
||||
viper.BindEnv("ORG")
|
||||
if h := viper.GetString("ORG"); h != "" {
|
||||
replFlags.Org = h
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
// task Command
|
||||
var taskCmd = &cobra.Command{
|
||||
Use: "task",
|
||||
Short: "task related commands",
|
||||
Short: "Task management commands",
|
||||
Run: taskF,
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ func taskF(cmd *cobra.Command, args []string) {
|
|||
|
||||
var logCmd = &cobra.Command{
|
||||
Use: "log",
|
||||
Short: "log related commands",
|
||||
Short: "Log related commands",
|
||||
Run: logF,
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ func logF(cmd *cobra.Command, args []string) {
|
|||
|
||||
var runCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "run related commands",
|
||||
Short: "Run related commands",
|
||||
Run: runF,
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ func init() {
|
|||
Run: userUpdateF,
|
||||
}
|
||||
|
||||
userUpdateCmd.Flags().StringVarP(&userUpdateFlags.id, "id", "i", "", "user id (required)")
|
||||
userUpdateCmd.Flags().StringVarP(&userUpdateFlags.name, "name", "n", "", "user name")
|
||||
userUpdateCmd.Flags().StringVarP(&userUpdateFlags.id, "id", "i", "", "The user ID (required)")
|
||||
userUpdateCmd.Flags().StringVarP(&userUpdateFlags.name, "name", "n", "", "The user name")
|
||||
userUpdateCmd.MarkFlagRequired("id")
|
||||
|
||||
userCmd.AddCommand(userUpdateCmd)
|
||||
|
@ -133,7 +133,7 @@ func init() {
|
|||
Run: userCreateF,
|
||||
}
|
||||
|
||||
userCreateCmd.Flags().StringVarP(&userCreateFlags.name, "name", "n", "", "user name (required)")
|
||||
userCreateCmd.Flags().StringVarP(&userCreateFlags.name, "name", "n", "", "The user name (required)")
|
||||
userCreateCmd.MarkFlagRequired("name")
|
||||
|
||||
userCmd.AddCommand(userCreateCmd)
|
||||
|
@ -182,8 +182,8 @@ func init() {
|
|||
Run: userFindF,
|
||||
}
|
||||
|
||||
userFindCmd.Flags().StringVarP(&userFindFlags.id, "id", "i", "", "user ID")
|
||||
userFindCmd.Flags().StringVarP(&userFindFlags.name, "name", "n", "", "user name")
|
||||
userFindCmd.Flags().StringVarP(&userFindFlags.id, "id", "i", "", "The user ID")
|
||||
userFindCmd.Flags().StringVarP(&userFindFlags.name, "name", "n", "", "The user name")
|
||||
|
||||
userCmd.AddCommand(userFindCmd)
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ func init() {
|
|||
Run: userDeleteF,
|
||||
}
|
||||
|
||||
userDeleteCmd.Flags().StringVarP(&userDeleteFlags.id, "id", "i", "", "user id (required)")
|
||||
userDeleteCmd.Flags().StringVarP(&userDeleteFlags.id, "id", "i", "", "The user ID (required)")
|
||||
userDeleteCmd.MarkFlagRequired("id")
|
||||
|
||||
userCmd.AddCommand(userDeleteCmd)
|
||||
|
|
|
@ -18,9 +18,9 @@ import (
|
|||
|
||||
var writeCmd = &cobra.Command{
|
||||
Use: "write line protocol or @/path/to/points.txt",
|
||||
Short: "Write points to influxdb",
|
||||
Long: `Write a single line of line protocol to influx db,
|
||||
or add an entire file specified with an @ prefix`,
|
||||
Short: "Write points to InfluxDB",
|
||||
Long: `Write a single line of line protocol to InfluxDB,
|
||||
or add an entire file specified with an @ prefix.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: fluxWriteF,
|
||||
}
|
||||
|
@ -34,31 +34,31 @@ var writeFlags struct {
|
|||
}
|
||||
|
||||
func init() {
|
||||
writeCmd.PersistentFlags().StringVar(&writeFlags.OrgID, "org-id", "", "id of the organization that owns the bucket")
|
||||
writeCmd.PersistentFlags().StringVar(&writeFlags.OrgID, "org-id", "", "The ID of the organization that owns the bucket")
|
||||
viper.BindEnv("ORG_ID")
|
||||
if h := viper.GetString("ORG_ID"); h != "" {
|
||||
writeFlags.OrgID = h
|
||||
}
|
||||
|
||||
writeCmd.PersistentFlags().StringVarP(&writeFlags.Org, "org", "o", "", "name of the organization that owns the bucket")
|
||||
writeCmd.PersistentFlags().StringVarP(&writeFlags.Org, "org", "o", "", "The name of the organization that owns the bucket")
|
||||
viper.BindEnv("ORG")
|
||||
if h := viper.GetString("ORG"); h != "" {
|
||||
writeFlags.Org = h
|
||||
}
|
||||
|
||||
writeCmd.PersistentFlags().StringVar(&writeFlags.BucketID, "bucket-id", "", "ID of destination bucket")
|
||||
writeCmd.PersistentFlags().StringVar(&writeFlags.BucketID, "bucket-id", "", "The ID of destination bucket")
|
||||
viper.BindEnv("BUCKET_ID")
|
||||
if h := viper.GetString("BUCKET_ID"); h != "" {
|
||||
writeFlags.BucketID = h
|
||||
}
|
||||
|
||||
writeCmd.PersistentFlags().StringVarP(&writeFlags.Bucket, "bucket", "b", "", "name of destination bucket")
|
||||
writeCmd.PersistentFlags().StringVarP(&writeFlags.Bucket, "bucket", "b", "", "The name of destination bucket")
|
||||
viper.BindEnv("BUCKET_NAME")
|
||||
if h := viper.GetString("BUCKET_NAME"); h != "" {
|
||||
writeFlags.Bucket = h
|
||||
}
|
||||
|
||||
writeCmd.PersistentFlags().StringVarP(&writeFlags.Precision, "precision", "p", "ns", "precision of the timestamps of the lines")
|
||||
writeCmd.PersistentFlags().StringVarP(&writeFlags.Precision, "precision", "p", "ns", "Precision of the timestamps of the lines")
|
||||
viper.BindEnv("PRECISION")
|
||||
if p := viper.GetString("PRECISION"); p != "" {
|
||||
writeFlags.Precision = p
|
||||
|
|
|
@ -377,9 +377,9 @@ func (e *Engine) DeleteBucket(orgID, bucketID platform.ID) error {
|
|||
// TODO(edd): we need to clean up how we're encoding the prefix so that we
|
||||
// don't have to remember to get it right everywhere we need to touch TSM data.
|
||||
encoded := tsdb.EncodeName(orgID, bucketID)
|
||||
prefix := models.EscapeMeasurement(encoded[:])
|
||||
name := models.EscapeMeasurement(encoded[:])
|
||||
|
||||
return e.engine.DeletePrefix(prefix, math.MinInt64, math.MaxInt64)
|
||||
return e.engine.DeleteBucket(name, math.MinInt64, math.MaxInt64)
|
||||
}
|
||||
|
||||
// DeleteSeriesRangeWithPredicate deletes all series data iterated over if fn returns
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package storage_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
platform "github.com/influxdata/influxdb"
|
||||
"github.com/influxdata/influxdb"
|
||||
"github.com/influxdata/influxdb/models"
|
||||
"github.com/influxdata/influxdb/storage"
|
||||
"github.com/influxdata/influxdb/tsdb"
|
||||
|
@ -149,6 +151,68 @@ func TestEngine_WriteAddNewField(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEngine_DeleteBucket(t *testing.T) {
|
||||
engine := NewDefaultEngine()
|
||||
defer engine.Close()
|
||||
engine.MustOpen()
|
||||
|
||||
pt := models.MustNewPoint(
|
||||
"cpu",
|
||||
models.NewTags(map[string]string{"host": "server"}),
|
||||
map[string]interface{}{"value": 1.0},
|
||||
time.Unix(1, 2),
|
||||
)
|
||||
|
||||
err := engine.Write1xPoints([]models.Point{pt})
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
pt = models.MustNewPoint(
|
||||
"cpu",
|
||||
models.NewTags(map[string]string{"host": "server"}),
|
||||
map[string]interface{}{"value": 1.0, "value2": 2.0},
|
||||
time.Unix(1, 3),
|
||||
)
|
||||
|
||||
// Same org, different bucket.
|
||||
err = engine.Write1xPointsWithOrgBucket([]models.Point{pt}, "3131313131313131", "8888888888888888")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
if got, exp := engine.SeriesCardinality(), int64(3); got != exp {
|
||||
t.Fatalf("got %d series, exp %d series in index", got, exp)
|
||||
}
|
||||
|
||||
// Remove the original bucket.
|
||||
if err := engine.DeleteBucket(engine.org, engine.bucket); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check only one bucket was removed.
|
||||
if got, exp := engine.SeriesCardinality(), int64(2); got != exp {
|
||||
t.Fatalf("got %d series, exp %d series in index", got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEngine_OpenClose(t *testing.T) {
|
||||
engine := NewDefaultEngine()
|
||||
engine.MustOpen()
|
||||
|
||||
if err := engine.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := engine.Open(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := engine.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures that when a shard is closed, it removes any series meta-data
|
||||
// from the index.
|
||||
func TestEngineClose_RemoveIndex(t *testing.T) {
|
||||
|
@ -201,8 +265,53 @@ func TestEngine_WALDisabled(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkDeleteBucket(b *testing.B) {
|
||||
var engine *Engine
|
||||
setup := func(card int) {
|
||||
engine = NewDefaultEngine()
|
||||
engine.MustOpen()
|
||||
|
||||
points := make([]models.Point, card)
|
||||
for i := 0; i < card; i++ {
|
||||
points[i] = models.MustNewPoint(
|
||||
"cpu",
|
||||
models.NewTags(map[string]string{"host": "server"}),
|
||||
map[string]interface{}{"value": i},
|
||||
time.Unix(1, 2),
|
||||
)
|
||||
}
|
||||
|
||||
if err := engine.Write1xPoints(points); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
card := int(math.Pow10(i))
|
||||
|
||||
b.Run(fmt.Sprintf("cardinality_%d", card), func(b *testing.B) {
|
||||
setup(card)
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err := engine.DeleteBucket(engine.org, engine.bucket); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
if err := engine.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
setup(card)
|
||||
b.StartTimer()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
type Engine struct {
|
||||
path string
|
||||
path string
|
||||
org, bucket influxdb.ID
|
||||
|
||||
*storage.Engine
|
||||
}
|
||||
|
||||
|
@ -211,8 +320,21 @@ func NewEngine(c storage.Config) *Engine {
|
|||
path, _ := ioutil.TempDir("", "storage_engine_test")
|
||||
|
||||
engine := storage.NewEngine(path, c)
|
||||
|
||||
org, err := influxdb.IDFromString("3131313131313131")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bucket, err := influxdb.IDFromString("3232323232323232")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &Engine{
|
||||
path: path,
|
||||
org: *org,
|
||||
bucket: *bucket,
|
||||
Engine: engine,
|
||||
}
|
||||
}
|
||||
|
@ -233,9 +355,26 @@ func (e *Engine) MustOpen() {
|
|||
// This allows us to use the old `models` package helper functions and still write
|
||||
// the points in the correct format.
|
||||
func (e *Engine) Write1xPoints(pts []models.Point) error {
|
||||
org, _ := platform.IDFromString("3131313131313131")
|
||||
bucket, _ := platform.IDFromString("3232323232323232")
|
||||
points, err := tsdb.ExplodePoints(*org, *bucket, pts)
|
||||
points, err := tsdb.ExplodePoints(e.org, e.bucket, pts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return e.Engine.WritePoints(points)
|
||||
}
|
||||
|
||||
// Write1xPointsWithOrgBucket writes 1.x points with the provided org and bucket id strings.
|
||||
func (e *Engine) Write1xPointsWithOrgBucket(pts []models.Point, org, bucket string) error {
|
||||
o, err := influxdb.IDFromString(org)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := influxdb.IDFromString(bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
points, err := tsdb.ExplodePoints(*o, *b, pts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -609,7 +609,7 @@ func DifferenceSeriesIDIterators(itr0, itr1 SeriesIDIterator) SeriesIDIterator {
|
|||
if a := NewSeriesIDSetIterators([]SeriesIDIterator{itr0, itr1}); a != nil {
|
||||
itr0.Close()
|
||||
itr1.Close()
|
||||
return NewSeriesIDSetIterator(a[0].SeriesIDSet().AndNot(a[1].SeriesIDSet()))
|
||||
return NewSeriesIDSetIterator(NewSeriesIDSetNegate(a[0].SeriesIDSet(), a[1].SeriesIDSet()))
|
||||
}
|
||||
|
||||
return &seriesIDDifferenceIterator{itrs: [2]SeriesIDIterator{itr0, itr1}}
|
||||
|
|
|
@ -27,6 +27,17 @@ func NewSeriesIDSet(a ...SeriesID) *SeriesIDSet {
|
|||
return ss
|
||||
}
|
||||
|
||||
// NewSeriesIDSetNegate returns a new SeriesIDSet containing all the elements in a
|
||||
// that are not present in b. That is, the set difference between a and b.
|
||||
func NewSeriesIDSetNegate(a, b *SeriesIDSet) *SeriesIDSet {
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
b.RLock()
|
||||
defer b.RUnlock()
|
||||
|
||||
return &SeriesIDSet{bitmap: roaring.AndNot(a.bitmap, b.bitmap)}
|
||||
}
|
||||
|
||||
// Bytes estimates the memory footprint of this SeriesIDSet, in bytes.
|
||||
func (s *SeriesIDSet) Bytes() int {
|
||||
var b int
|
||||
|
@ -170,15 +181,13 @@ func (s *SeriesIDSet) And(other *SeriesIDSet) *SeriesIDSet {
|
|||
return &SeriesIDSet{bitmap: roaring.And(s.bitmap, other.bitmap)}
|
||||
}
|
||||
|
||||
// AndNot returns a new SeriesIDSet containing elements that were present in s,
|
||||
// but not present in other.
|
||||
func (s *SeriesIDSet) AndNot(other *SeriesIDSet) *SeriesIDSet {
|
||||
// RemoveSet removes all values in other from s, if they exist.
|
||||
func (s *SeriesIDSet) RemoveSet(other *SeriesIDSet) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
other.RLock()
|
||||
defer other.RUnlock()
|
||||
|
||||
return &SeriesIDSet{bitmap: roaring.AndNot(s.bitmap, other.bitmap)}
|
||||
s.bitmap.AndNot(other.bitmap)
|
||||
}
|
||||
|
||||
// ForEach calls f for each id in the set. The function is applied to the IDs
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestSeriesIDSet_AndNot(t *testing.T) {
|
||||
func TestSeriesIDSet_NewSeriesIDSetNegate(t *testing.T) {
|
||||
examples := [][3][]uint64{
|
||||
[3][]uint64{
|
||||
{1, 10, 20, 30},
|
||||
|
@ -55,7 +55,7 @@ func TestSeriesIDSet_AndNot(t *testing.T) {
|
|||
expected.Add(NewSeriesID(v))
|
||||
}
|
||||
|
||||
got := a.AndNot(b)
|
||||
got := NewSeriesIDSetNegate(a, b)
|
||||
if got.String() != expected.String() {
|
||||
t.Fatalf("got %s, expected %s", got.String(), expected.String())
|
||||
}
|
||||
|
@ -63,6 +63,59 @@ func TestSeriesIDSet_AndNot(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSeriesIDSet_RemoveSet(t *testing.T) {
|
||||
examples := [][3][]uint64{
|
||||
[3][]uint64{
|
||||
{1, 10, 20, 30},
|
||||
{10, 12, 13, 14, 20},
|
||||
{1, 30},
|
||||
},
|
||||
[3][]uint64{
|
||||
{},
|
||||
{10},
|
||||
{},
|
||||
},
|
||||
[3][]uint64{
|
||||
{1, 10, 20, 30},
|
||||
{1, 10, 20, 30},
|
||||
{},
|
||||
},
|
||||
[3][]uint64{
|
||||
{1, 10},
|
||||
{1, 10, 100},
|
||||
{},
|
||||
},
|
||||
[3][]uint64{
|
||||
{1, 10},
|
||||
{},
|
||||
{1, 10},
|
||||
},
|
||||
}
|
||||
|
||||
for i, example := range examples {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
// Build sets.
|
||||
a, b := NewSeriesIDSet(), NewSeriesIDSet()
|
||||
for _, v := range example[0] {
|
||||
a.Add(NewSeriesID(v))
|
||||
}
|
||||
for _, v := range example[1] {
|
||||
b.Add(NewSeriesID(v))
|
||||
}
|
||||
|
||||
expected := NewSeriesIDSet()
|
||||
for _, v := range example[2] {
|
||||
expected.Add(NewSeriesID(v))
|
||||
}
|
||||
|
||||
a.RemoveSet(b)
|
||||
if a.String() != expected.String() {
|
||||
t.Fatalf("got %s, expected %s", a.String(), expected.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that cloning is race-free.
|
||||
func TestSeriesIDSet_Clone_Race(t *testing.T) {
|
||||
main := NewSeriesIDSet()
|
||||
|
@ -556,6 +609,78 @@ func BenchmarkSeriesIDSet_Remove(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
// BenchmarkSeriesIDSet_MassRemove benchmarks the cost of removing a large set of values.
|
||||
func BenchmarkSeriesIDSet_MassRemove(b *testing.B) {
|
||||
var size = uint64(1000000)
|
||||
// Setup...
|
||||
set = NewSeriesIDSet()
|
||||
for i := uint64(0); i < size; i++ {
|
||||
set.Add(NewSeriesID(i))
|
||||
}
|
||||
|
||||
// Remove one at a time
|
||||
b.Run(fmt.Sprint("cardinality_1000000_remove_each"), func(b *testing.B) {
|
||||
clone := set.Clone()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := uint64(0); j < size/2; j++ {
|
||||
clone.RemoveNoLock(NewSeriesID(j))
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
clone = set.Clone()
|
||||
b.StartTimer()
|
||||
}
|
||||
})
|
||||
|
||||
// This is the case where a target series id set exists.
|
||||
b.Run(fmt.Sprint("cardinality_1000000_remove_set_exists"), func(b *testing.B) {
|
||||
clone := set.Clone()
|
||||
other := NewSeriesIDSet()
|
||||
for j := uint64(0); j < size/2; j++ {
|
||||
other.AddNoLock(NewSeriesID(j))
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
clone.RemoveSet(other)
|
||||
b.StopTimer()
|
||||
clone = set.Clone()
|
||||
b.StartTimer()
|
||||
}
|
||||
})
|
||||
|
||||
// Make a target series id set and negate it
|
||||
b.Run(fmt.Sprint("cardinality_1000000_remove_set"), func(b *testing.B) {
|
||||
clone := set.Clone()
|
||||
for i := 0; i < b.N; i++ {
|
||||
other := NewSeriesIDSet()
|
||||
for j := uint64(0); j < size/2; j++ {
|
||||
other.AddNoLock(NewSeriesID(j))
|
||||
}
|
||||
|
||||
clone.RemoveSet(other)
|
||||
b.StopTimer()
|
||||
clone = set.Clone()
|
||||
b.StartTimer()
|
||||
}
|
||||
})
|
||||
|
||||
// This is the case where a new result set is created.
|
||||
b.Run(fmt.Sprint("cardinality_1000000_remove_set_new"), func(b *testing.B) {
|
||||
clone := set.Clone()
|
||||
other := NewSeriesIDSet()
|
||||
for j := uint64(0); j < size/2; j++ {
|
||||
other.AddNoLock(NewSeriesID(j))
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = NewSeriesIDSetNegate(clone, other)
|
||||
b.StopTimer()
|
||||
clone = set.Clone()
|
||||
b.StartTimer()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Typical benchmarks for a laptop:
|
||||
//
|
||||
// BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_1/shards_1-4 200000 8095 ns/op 16656 B/op 11 allocs/op
|
||||
|
|
|
@ -153,6 +153,13 @@ func (c *TagValueSeriesIDCache) Delete(name, key, value []byte, x tsdb.SeriesID)
|
|||
c.Unlock()
|
||||
}
|
||||
|
||||
// DeleteMeasurement removes all cached entries for the provided measurement name.
|
||||
func (c *TagValueSeriesIDCache) DeleteMeasurement(name []byte) {
|
||||
c.Lock()
|
||||
delete(c.cache, string(name))
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// delete removes x from the tuple {name, key, value} if it exists.
|
||||
func (c *TagValueSeriesIDCache) delete(name, key, value []byte, x tsdb.SeriesID) {
|
||||
if mmap, ok := c.cache[string(name)]; ok {
|
||||
|
|
|
@ -387,7 +387,7 @@ func (fs *FileSet) TagValueSeriesIDIterator(name, key, value []byte) (tsdb.Serie
|
|||
|
||||
// Remove tombstones set in previous file.
|
||||
if ftss != nil && ftss.Cardinality() > 0 {
|
||||
ss = ss.AndNot(ftss)
|
||||
ss.RemoveSet(ftss)
|
||||
}
|
||||
|
||||
// Fetch tag value series set for this file and merge into overall set.
|
||||
|
|
|
@ -592,13 +592,15 @@ func (i *Index) DropMeasurement(name []byte) error {
|
|||
}()
|
||||
}
|
||||
|
||||
// Remove any cached bitmaps for the measurement.
|
||||
i.tagValueCache.DeleteMeasurement(name)
|
||||
|
||||
// Check for error
|
||||
for i := 0; i < cap(errC); i++ {
|
||||
if err := <-errC; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -593,6 +593,24 @@ func (f *LogFile) DeleteSeriesID(id tsdb.SeriesID) error {
|
|||
return f.FlushAndSync()
|
||||
}
|
||||
|
||||
// DeleteSeriesIDList marks a tombstone for all the series IDs. DeleteSeriesIDList
|
||||
// should be preferred to repeatedly calling DeleteSeriesID for many series ids.
|
||||
func (f *LogFile) DeleteSeriesIDList(ids []tsdb.SeriesID) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
for _, id := range ids {
|
||||
e := LogEntry{Flag: LogEntrySeriesTombstoneFlag, SeriesID: id}
|
||||
if err := f.appendEntry(&e); err != nil {
|
||||
return err
|
||||
}
|
||||
f.execEntry(&e)
|
||||
}
|
||||
|
||||
// Flush buffer and sync to disk.
|
||||
return f.FlushAndSync()
|
||||
}
|
||||
|
||||
// SeriesN returns the total number of series in the file.
|
||||
func (f *LogFile) SeriesN() (n uint64) {
|
||||
f.mu.RLock()
|
||||
|
|
|
@ -626,8 +626,14 @@ func (p *Partition) DropMeasurement(name []byte) error {
|
|||
}
|
||||
|
||||
// Delete all series.
|
||||
// TODO(edd): it's not clear to me why we have to delete all series IDs from
|
||||
// the index when we could just mark the measurement as deleted.
|
||||
if itr := fs.MeasurementSeriesIDIterator(name); itr != nil {
|
||||
defer itr.Close()
|
||||
|
||||
// 1024 is assuming that typically a bucket (measurement) will have at least
|
||||
// 1024 series in it.
|
||||
all := make([]tsdb.SeriesID, 0, 1024)
|
||||
for {
|
||||
elem, err := itr.Next()
|
||||
if err != nil {
|
||||
|
@ -635,10 +641,19 @@ func (p *Partition) DropMeasurement(name []byte) error {
|
|||
} else if elem.SeriesID.IsZero() {
|
||||
break
|
||||
}
|
||||
if err := p.activeLogFile.DeleteSeriesID(elem.SeriesID); err != nil {
|
||||
return err
|
||||
}
|
||||
all = append(all, elem.SeriesID)
|
||||
|
||||
// Update series set.
|
||||
p.seriesIDSet.Remove(elem.SeriesID)
|
||||
}
|
||||
|
||||
if err := p.activeLogFile.DeleteSeriesIDList(all); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.tracker.AddSeriesDropped(uint64(len(all)))
|
||||
p.tracker.SubSeries(uint64(len(all)))
|
||||
|
||||
if err = itr.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,10 +7,14 @@ import (
|
|||
|
||||
"github.com/influxdata/influxdb/models"
|
||||
"github.com/influxdata/influxdb/pkg/bytesutil"
|
||||
"github.com/influxdata/influxdb/tsdb"
|
||||
"github.com/influxdata/influxql"
|
||||
)
|
||||
|
||||
func (e *Engine) DeletePrefix(prefix []byte, min, max int64) error {
|
||||
// DeleteBucket removes all TSM data belonging to a bucket, and removes all index
|
||||
// and series file data associated with the bucket. The provided time range ensures
|
||||
// that only bucket data for that range is removed.
|
||||
func (e *Engine) DeleteBucket(name []byte, min, max int64) error {
|
||||
// TODO(jeff): we need to block writes to this prefix while deletes are in progress
|
||||
// otherwise we can end up in a situation where we have staged data in the cache or
|
||||
// WAL that was deleted from the index, or worse. This needs to happen at a higher
|
||||
|
@ -63,7 +67,7 @@ func (e *Engine) DeletePrefix(prefix []byte, min, max int64) error {
|
|||
possiblyDead.keys = make(map[string]struct{})
|
||||
|
||||
if err := e.FileStore.Apply(func(r TSMFile) error {
|
||||
return r.DeletePrefix(prefix, min, max, func(key []byte) {
|
||||
return r.DeletePrefix(name, min, max, func(key []byte) {
|
||||
possiblyDead.Lock()
|
||||
possiblyDead.keys[string(key)] = struct{}{}
|
||||
possiblyDead.Unlock()
|
||||
|
@ -79,7 +83,7 @@ func (e *Engine) DeletePrefix(prefix []byte, min, max int64) error {
|
|||
|
||||
// ApplySerialEntryFn cannot return an error in this invocation.
|
||||
_ = e.Cache.ApplyEntryFn(func(k []byte, _ *entry) error {
|
||||
if bytes.HasPrefix(k, prefix) {
|
||||
if bytes.HasPrefix(k, name) {
|
||||
if deleteKeys == nil {
|
||||
deleteKeys = make([][]byte, 0, 10000)
|
||||
}
|
||||
|
@ -107,10 +111,10 @@ func (e *Engine) DeletePrefix(prefix []byte, min, max int64) error {
|
|||
possiblyDead.RLock()
|
||||
defer possiblyDead.RUnlock()
|
||||
|
||||
iter := r.Iterator(prefix)
|
||||
iter := r.Iterator(name)
|
||||
for i := 0; iter.Next(); i++ {
|
||||
key := iter.Key()
|
||||
if !bytes.HasPrefix(key, prefix) {
|
||||
if !bytes.HasPrefix(key, name) {
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -143,6 +147,46 @@ func (e *Engine) DeletePrefix(prefix []byte, min, max int64) error {
|
|||
// TODO(jeff): it's also important that all of the deletes happen atomically with
|
||||
// the deletes of the data in the tsm files.
|
||||
|
||||
// In this case the entire measurement (bucket) can be removed from the index.
|
||||
if min == math.MinInt64 && max == math.MaxInt64 {
|
||||
// Build up a set of series IDs that we need to remove from the series file.
|
||||
set := tsdb.NewSeriesIDSet()
|
||||
itr, err := e.index.MeasurementSeriesIDIterator(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var elem tsdb.SeriesIDElem
|
||||
for elem, err = itr.Next(); err != nil; elem, err = itr.Next() {
|
||||
if elem.SeriesID.IsZero() {
|
||||
break
|
||||
}
|
||||
|
||||
set.AddNoLock(elem.SeriesID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if err := itr.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove the measurement from the index before the series file.
|
||||
if err := e.index.DropMeasurement(name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Iterate over the series ids we previously extracted from the index
|
||||
// and remove from the series file.
|
||||
set.ForEachNoLock(func(id tsdb.SeriesID) {
|
||||
if err = e.sfile.DeleteSeriesID(id); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// This is the slow path, when not dropping the entire bucket (measurement)
|
||||
for key := range possiblyDead.keys {
|
||||
// TODO(jeff): ugh reduce copies here
|
||||
keyb := []byte(key)
|
||||
|
@ -157,6 +201,7 @@ func (e *Engine) DeletePrefix(prefix []byte, min, max int64) error {
|
|||
if err := e.index.DropSeries(sid, keyb, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.sfile.DeleteSeriesID(sid); err != nil {
|
||||
return err
|
||||
}
|
|
@ -44,7 +44,7 @@ func TestEngine_DeletePrefix(t *testing.T) {
|
|||
t.Fatalf("series count mismatch: exp %v, got %v", exp, got)
|
||||
}
|
||||
|
||||
if err := e.DeletePrefix([]byte("cpu"), 0, 3); err != nil {
|
||||
if err := e.DeleteBucket([]byte("cpu"), 0, 3); err != nil {
|
||||
t.Fatalf("failed to delete series: %v", err)
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ func TestEngine_DeletePrefix(t *testing.T) {
|
|||
iter.Close()
|
||||
|
||||
// Deleting remaining series should remove them from the series.
|
||||
if err := e.DeletePrefix([]byte("cpu"), 0, 9); err != nil {
|
||||
if err := e.DeleteBucket([]byte("cpu"), 0, 9); err != nil {
|
||||
t.Fatalf("failed to delete series: %v", err)
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Libraries
|
||||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
|
||||
// Components
|
||||
import SaveAsButton from 'src/dataExplorer/components/SaveAsButton'
|
||||
import SaveAsCellForm from 'src/dataExplorer/components/SaveAsCellForm'
|
||||
|
||||
const setup = () => {
|
||||
const wrapper = shallow(<SaveAsButton />)
|
||||
|
||||
return {wrapper}
|
||||
}
|
||||
|
||||
describe('SaveAsButton', () => {
|
||||
const {wrapper} = setup()
|
||||
describe('rendering', () => {
|
||||
it('renders', () => {
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('save as cell form', () => {
|
||||
it('defaults to save as cell form', () => {
|
||||
const saveAsCellForm = wrapper.find(SaveAsCellForm)
|
||||
|
||||
expect(saveAsCellForm.exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -45,11 +45,11 @@ class SaveAsButton extends PureComponent<Props, State> {
|
|||
icon={IconFont.Export}
|
||||
text="Save As"
|
||||
onClick={this.handleShowOverlay}
|
||||
color={ComponentColor.Success}
|
||||
color={ComponentColor.Primary}
|
||||
titleText="Save your query as a Dashboard Cell or a Task"
|
||||
/>
|
||||
<OverlayTechnology visible={isOverlayVisible}>
|
||||
<OverlayContainer>
|
||||
<OverlayContainer maxWidth={600}>
|
||||
<OverlayHeading
|
||||
title="Save As"
|
||||
onDismiss={this.handleHideOverlay}
|
||||
|
@ -61,6 +61,7 @@ class SaveAsButton extends PureComponent<Props, State> {
|
|||
active={saveAsOption === SaveAsOption.Dashboard}
|
||||
value={SaveAsOption.Dashboard}
|
||||
onClick={this.handleSetSaveAsOption}
|
||||
data-test="cell-radio-button"
|
||||
>
|
||||
Dashboard Cell
|
||||
</Radio.Button>
|
||||
|
@ -68,15 +69,13 @@ class SaveAsButton extends PureComponent<Props, State> {
|
|||
active={saveAsOption === SaveAsOption.Task}
|
||||
value={SaveAsOption.Task}
|
||||
onClick={this.handleSetSaveAsOption}
|
||||
data-test="task-radio-button"
|
||||
>
|
||||
Task
|
||||
</Radio.Button>
|
||||
</Radio>
|
||||
</div>
|
||||
{saveAsOption === SaveAsOption.Dashboard && (
|
||||
<SaveAsCellForm dismiss={this.handleHideOverlay} />
|
||||
)}
|
||||
{saveAsOption === SaveAsOption.Task && <SaveAsTaskForm />}
|
||||
{this.saveAsForm}
|
||||
</OverlayBody>
|
||||
</OverlayContainer>
|
||||
</OverlayTechnology>
|
||||
|
@ -84,6 +83,16 @@ class SaveAsButton extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private get saveAsForm(): JSX.Element {
|
||||
const {saveAsOption} = this.state
|
||||
|
||||
if (saveAsOption === SaveAsOption.Dashboard) {
|
||||
return <SaveAsCellForm dismiss={this.handleHideOverlay} />
|
||||
} else if (saveAsOption === SaveAsOption.Task) {
|
||||
return <SaveAsTaskForm dismiss={this.handleHideOverlay} />
|
||||
}
|
||||
}
|
||||
|
||||
private handleShowOverlay = () => {
|
||||
this.setState({isOverlayVisible: true})
|
||||
}
|
||||
|
|
|
@ -1,7 +1,147 @@
|
|||
import React from 'react'
|
||||
// Libraries
|
||||
import React, {PureComponent, ChangeEvent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import _ from 'lodash'
|
||||
|
||||
const SaveAsTaskForm = () => {
|
||||
return <div>Tasks Not implemented</div>
|
||||
// Components
|
||||
import TaskForm from 'src/tasks/components/TaskForm'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
saveNewScript,
|
||||
setTaskOption,
|
||||
clearTask,
|
||||
setNewScript,
|
||||
} from 'src/tasks/actions/v2'
|
||||
|
||||
// Types
|
||||
import {AppState, Organization} from 'src/types/v2'
|
||||
import {
|
||||
TaskSchedule,
|
||||
TaskOptions,
|
||||
TaskOptionKeys,
|
||||
} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {DashboardDraftQuery} from 'src/types/v2/dashboards'
|
||||
|
||||
interface OwnProps {
|
||||
dismiss: () => void
|
||||
}
|
||||
|
||||
export default SaveAsTaskForm
|
||||
interface DispatchProps {
|
||||
saveNewScript: typeof saveNewScript
|
||||
setTaskOption: typeof setTaskOption
|
||||
clearTask: typeof clearTask
|
||||
setNewScript: typeof setNewScript
|
||||
}
|
||||
|
||||
interface StateProps {
|
||||
orgs: Organization[]
|
||||
taskOptions: TaskOptions
|
||||
draftQueries: DashboardDraftQuery[]
|
||||
activeQueryIndex: number
|
||||
}
|
||||
|
||||
type Props = StateProps & OwnProps & DispatchProps
|
||||
|
||||
class SaveAsTaskForm extends PureComponent<Props> {
|
||||
public componentDidMount() {
|
||||
const {setTaskOption, setNewScript} = this.props
|
||||
|
||||
setTaskOption({
|
||||
key: 'taskScheduleType',
|
||||
value: TaskSchedule.interval,
|
||||
})
|
||||
|
||||
setNewScript(this.activeScript)
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
const {clearTask} = this.props
|
||||
|
||||
clearTask()
|
||||
}
|
||||
public render() {
|
||||
const {orgs, taskOptions, dismiss} = this.props
|
||||
|
||||
return (
|
||||
<TaskForm
|
||||
orgs={orgs}
|
||||
taskOptions={taskOptions}
|
||||
onChangeScheduleType={this.handleChangeScheduleType}
|
||||
onChangeInput={this.handleChangeInput}
|
||||
onChangeTaskOrgID={this.handleChangeTaskOrgID}
|
||||
isInOverlay={true}
|
||||
onSubmit={this.handleSubmit}
|
||||
canSubmit={this.isFormValid}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private get isFormValid(): boolean {
|
||||
const {
|
||||
taskOptions: {name, cron, interval},
|
||||
} = this.props
|
||||
const hasSchedule = !!cron || !!interval
|
||||
|
||||
return hasSchedule && !!name && !!this.activeScript
|
||||
}
|
||||
|
||||
private get activeScript(): string {
|
||||
const {draftQueries, activeQueryIndex} = this.props
|
||||
|
||||
return _.get(draftQueries, `${activeQueryIndex}.text`)
|
||||
}
|
||||
|
||||
private handleSubmit = () => {
|
||||
const {saveNewScript} = this.props
|
||||
saveNewScript()
|
||||
}
|
||||
|
||||
private handleChangeTaskOrgID = (orgID: string) => {
|
||||
const {setTaskOption} = this.props
|
||||
|
||||
setTaskOption({key: 'orgID', value: orgID})
|
||||
}
|
||||
|
||||
private handleChangeScheduleType = (taskScheduleType: TaskSchedule) => {
|
||||
const {setTaskOption} = this.props
|
||||
|
||||
setTaskOption({key: 'taskScheduleType', value: taskScheduleType})
|
||||
}
|
||||
|
||||
private handleChangeInput = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const {setTaskOption} = this.props
|
||||
|
||||
const key = e.target.name as TaskOptionKeys
|
||||
const value = e.target.value
|
||||
|
||||
setTaskOption({key, value})
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {
|
||||
orgs,
|
||||
tasks,
|
||||
timeMachines: {
|
||||
timeMachines: {de},
|
||||
},
|
||||
} = state
|
||||
|
||||
const {draftQueries, activeQueryIndex} = de
|
||||
|
||||
return {orgs, taskOptions: tasks.taskOptions, draftQueries, activeQueryIndex}
|
||||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
saveNewScript,
|
||||
setTaskOption,
|
||||
clearTask,
|
||||
setNewScript,
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps>(
|
||||
mstp,
|
||||
mdtp
|
||||
)(SaveAsTaskForm)
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SaveAsButton rendering renders 1`] = `
|
||||
<Fragment>
|
||||
<Button
|
||||
active={false}
|
||||
color="primary"
|
||||
icon="export"
|
||||
onClick={[Function]}
|
||||
shape="none"
|
||||
size="sm"
|
||||
status="default"
|
||||
text="Save As"
|
||||
titleText="Save your query as a Dashboard Cell or a Task"
|
||||
type="button"
|
||||
/>
|
||||
<OverlayTechnology
|
||||
visible={false}
|
||||
>
|
||||
<OverlayContainer
|
||||
maxWidth={600}
|
||||
>
|
||||
<OverlayHeading
|
||||
onDismiss={[Function]}
|
||||
title="Save As"
|
||||
/>
|
||||
<OverlayBody>
|
||||
<div
|
||||
className="save-as--options"
|
||||
>
|
||||
<Radio
|
||||
color="primary"
|
||||
shape="none"
|
||||
size="sm"
|
||||
>
|
||||
<RadioButton
|
||||
active={true}
|
||||
data-test="cell-radio-button"
|
||||
disabled={false}
|
||||
disabledTitleText="This option is disabled"
|
||||
onClick={[Function]}
|
||||
value="dashboard"
|
||||
>
|
||||
Dashboard Cell
|
||||
</RadioButton>
|
||||
<RadioButton
|
||||
active={false}
|
||||
data-test="task-radio-button"
|
||||
disabled={false}
|
||||
disabledTitleText="This option is disabled"
|
||||
onClick={[Function]}
|
||||
value="task"
|
||||
>
|
||||
Task
|
||||
</RadioButton>
|
||||
</Radio>
|
||||
</div>
|
||||
<Connect(SaveAsCellForm)
|
||||
dismiss={[Function]}
|
||||
/>
|
||||
</OverlayBody>
|
||||
</OverlayContainer>
|
||||
</OverlayTechnology>
|
||||
</Fragment>
|
||||
`;
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Getting Started Widget
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@import 'src/style/modules';
|
||||
|
||||
$getting-started--gutter: $ix-marg-b;
|
||||
|
||||
.getting-started {
|
||||
margin-top: $ix-marg-b;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.getting-started--container {
|
||||
width: 100%;
|
||||
padding-bottom: 100%;
|
||||
margin-bottom: $getting-started--gutter;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.getting-started--card {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: $g4-onyx;
|
||||
border-radius: $radius;
|
||||
text-align: center;
|
||||
padding: $ix-marg-c;
|
||||
transition: background-color 0.25s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
&:hover {
|
||||
background-color: $g5-pepper;
|
||||
cursor: pointer;
|
||||
|
||||
.gradient-border {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.getting-started--title {
|
||||
font-weight: 500;
|
||||
color: $g11-sidewalk;
|
||||
font-size: 20px;
|
||||
transition: color 0.25s ease;
|
||||
margin: 0;
|
||||
margin-bottom: $ix-marg-e;
|
||||
|
||||
.getting-started--card:hover & {
|
||||
color: $g20-white;
|
||||
}
|
||||
}
|
||||
|
||||
.getting-started--image {
|
||||
width: 100%;
|
||||
height: 70%;
|
||||
background-size: cover;
|
||||
|
||||
> svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: $grid--breakpoint-sm) {
|
||||
.getting-started--container {
|
||||
width: calc(33.3333% - #{$getting-started--gutter});
|
||||
padding-bottom: calc(50% - #{$getting-started--gutter});
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.getting-started--title {
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: $grid--breakpoint-md) {
|
||||
.getting-started--container {
|
||||
width: calc(33.3333% - #{$getting-started--gutter});
|
||||
padding-bottom: calc(33.3333% - #{$getting-started--gutter});
|
||||
}
|
||||
.getting-started--title {
|
||||
font-size: 19px;
|
||||
margin-bottom: $ix-marg-d;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {Link} from 'react-router'
|
||||
|
||||
// Components
|
||||
import GradientBorder from 'src/shared/components/cells/GradientBorder'
|
||||
import DashboardingGraphic from 'src/me/graphics/DashboardingGraphic'
|
||||
import ExploreGraphic from 'src/me/graphics/ExploreGraphic'
|
||||
import CollectorGraphic from 'src/me/graphics/CollectorGraphic'
|
||||
|
||||
// Styles
|
||||
import 'src/me/components/GettingStarted.scss'
|
||||
|
||||
export default class GettingStarted extends PureComponent {
|
||||
public render() {
|
||||
return (
|
||||
<div className="getting-started">
|
||||
<div className="getting-started--container">
|
||||
<Link to={`/data-explorer`} className="getting-started--card">
|
||||
<GradientBorder />
|
||||
<CollectorGraphic />
|
||||
<h3 className="getting-started--title">
|
||||
Configure a<br />
|
||||
Data Collector
|
||||
</h3>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="getting-started--container">
|
||||
<Link to={`/dashboards`} className="getting-started--card">
|
||||
<GradientBorder />
|
||||
<DashboardingGraphic />
|
||||
<h3 className="getting-started--title">
|
||||
Build a Monitoring
|
||||
<br />
|
||||
Dashboard
|
||||
</h3>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="getting-started--container">
|
||||
<Link to={`/data-explorer`} className="getting-started--card">
|
||||
<GradientBorder />
|
||||
<ExploreGraphic />
|
||||
<h3 className="getting-started--title">
|
||||
Explore your data
|
||||
<br />
|
||||
using Flux
|
||||
</h3>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -4,21 +4,31 @@ import React, {PureComponent} from 'react'
|
|||
// Components
|
||||
import {Page} from 'src/pageLayout'
|
||||
|
||||
// Constants
|
||||
import {generateRandomGreeting} from 'src/me/constants'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
userName: string
|
||||
}
|
||||
|
||||
export default class UserPageHeader extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {title} = this.props
|
||||
|
||||
return (
|
||||
<Page.Header fullWidth={false}>
|
||||
<Page.Header.Left>
|
||||
<Page.Title title={title} />
|
||||
</Page.Header.Left>
|
||||
<Page.Header.Left>{this.title}</Page.Header.Left>
|
||||
<Page.Header.Right />
|
||||
</Page.Header>
|
||||
)
|
||||
}
|
||||
|
||||
private get title(): JSX.Element {
|
||||
const {userName} = this.props
|
||||
|
||||
const {text, language} = generateRandomGreeting()
|
||||
|
||||
const title = `${text}, ${userName}!`
|
||||
const altText = `That's how you say hello in ${language}`
|
||||
|
||||
return <Page.Title title={title} altText={altText} />
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,48 +15,8 @@ import {Authorization, Permission} from 'src/api'
|
|||
// Actions
|
||||
import {NotificationAction} from 'src/types'
|
||||
|
||||
const {Orgs, Users, Buckets, Tasks} = Permission.ResourceEnum
|
||||
const {Write, Read} = Permission.ActionEnum
|
||||
|
||||
export interface TestPermission {
|
||||
resource: Permission.ResourceEnum
|
||||
actions: Permission.ActionEnum[]
|
||||
id?: string
|
||||
name?: string
|
||||
orgID?: string
|
||||
orgName?: string
|
||||
}
|
||||
|
||||
const testPerms: TestPermission[] = [
|
||||
{
|
||||
resource: Users,
|
||||
actions: [Write, Read],
|
||||
},
|
||||
{
|
||||
resource: Orgs,
|
||||
id: '1',
|
||||
name: 'myorg',
|
||||
actions: [Read],
|
||||
},
|
||||
{
|
||||
resource: Buckets,
|
||||
id: '2',
|
||||
name: 'telegraf',
|
||||
actions: [Read],
|
||||
},
|
||||
{
|
||||
resource: Tasks, // resource will be Task `task`
|
||||
name: 'task1',
|
||||
actions: [Read],
|
||||
},
|
||||
{
|
||||
resource: Tasks, // resource will be Task `task`
|
||||
id: '2',
|
||||
name: 'task1',
|
||||
actions: [Read],
|
||||
},
|
||||
]
|
||||
|
||||
interface Props {
|
||||
onNotify: NotificationAction
|
||||
auth: Authorization
|
||||
|
@ -67,7 +27,7 @@ const actions = [Read, Write]
|
|||
|
||||
export default class ViewTokenOverlay extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {description} = this.props.auth
|
||||
const {description, permissions} = this.props.auth
|
||||
const {onNotify} = this.props
|
||||
|
||||
return (
|
||||
|
@ -79,7 +39,7 @@ export default class ViewTokenOverlay extends PureComponent<Props> {
|
|||
mode={PermissionsWidgetMode.Read}
|
||||
heightPixels={500}
|
||||
>
|
||||
{testPerms.map((p, i) => {
|
||||
{permissions.map((p, i) => {
|
||||
return (
|
||||
<PermissionsWidget.Section
|
||||
key={i}
|
||||
|
@ -105,12 +65,10 @@ export default class ViewTokenOverlay extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private selected = (
|
||||
permission: TestPermission,
|
||||
permission: Permission,
|
||||
action: Permission.ActionEnum
|
||||
): PermissionsWidgetSelection => {
|
||||
const isSelected = permission.actions.some(a => a === action)
|
||||
|
||||
if (isSelected) {
|
||||
if (permission.action === action) {
|
||||
return PermissionsWidgetSelection.Selected
|
||||
}
|
||||
|
||||
|
@ -118,13 +76,13 @@ export default class ViewTokenOverlay extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private itemID = (
|
||||
permission: TestPermission,
|
||||
permission: Permission,
|
||||
action: Permission.ActionEnum
|
||||
): string => {
|
||||
return `${permission.id || permission.resource}-${action}`
|
||||
}
|
||||
|
||||
private id = (permission: TestPermission): string => {
|
||||
private id = (permission: Permission): string => {
|
||||
return permission.id || permission.resource
|
||||
}
|
||||
|
||||
|
|
|
@ -283,10 +283,10 @@ exports[`Account rendering renders! 1`] = `
|
|||
}
|
||||
>
|
||||
<PermissionsWidgetSection
|
||||
id="users"
|
||||
id="orgs"
|
||||
key=".$0"
|
||||
mode="read"
|
||||
title="users:*"
|
||||
title="orgs:*"
|
||||
>
|
||||
<section
|
||||
className="permissions-widget--section"
|
||||
|
@ -297,28 +297,28 @@ exports[`Account rendering renders! 1`] = `
|
|||
<h3
|
||||
className="permissions-widget--section-title"
|
||||
>
|
||||
users:*
|
||||
orgs:*
|
||||
</h3>
|
||||
</header>
|
||||
<ul
|
||||
className="permissions-widget--section-list"
|
||||
>
|
||||
<PermissionsWidgetItem
|
||||
id="users-read"
|
||||
id="orgs-read"
|
||||
key=".$0"
|
||||
label="read"
|
||||
mode="read"
|
||||
selected="selected"
|
||||
selected="unselected"
|
||||
>
|
||||
<li
|
||||
className="permissions-widget--item selected"
|
||||
className="permissions-widget--item unselected"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="permissions-widget--icon"
|
||||
>
|
||||
<span
|
||||
className="icon checkmark"
|
||||
className="icon remove"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
|
@ -329,7 +329,7 @@ exports[`Account rendering renders! 1`] = `
|
|||
</li>
|
||||
</PermissionsWidgetItem>
|
||||
<PermissionsWidgetItem
|
||||
id="users-write"
|
||||
id="orgs-write"
|
||||
key=".$1"
|
||||
label="write"
|
||||
mode="read"
|
||||
|
@ -357,10 +357,10 @@ exports[`Account rendering renders! 1`] = `
|
|||
</section>
|
||||
</PermissionsWidgetSection>
|
||||
<PermissionsWidgetSection
|
||||
id="1"
|
||||
id="buckets"
|
||||
key=".$1"
|
||||
mode="read"
|
||||
title="orgs:myorg"
|
||||
title="buckets:*"
|
||||
>
|
||||
<section
|
||||
className="permissions-widget--section"
|
||||
|
@ -371,42 +371,17 @@ exports[`Account rendering renders! 1`] = `
|
|||
<h3
|
||||
className="permissions-widget--section-title"
|
||||
>
|
||||
orgs:myorg
|
||||
buckets:*
|
||||
</h3>
|
||||
</header>
|
||||
<ul
|
||||
className="permissions-widget--section-list"
|
||||
>
|
||||
<PermissionsWidgetItem
|
||||
id="1-read"
|
||||
id="buckets-read"
|
||||
key=".$0"
|
||||
label="read"
|
||||
mode="read"
|
||||
selected="selected"
|
||||
>
|
||||
<li
|
||||
className="permissions-widget--item selected"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="permissions-widget--icon"
|
||||
>
|
||||
<span
|
||||
className="icon checkmark"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
className="permissions-widget--item-label"
|
||||
>
|
||||
read
|
||||
</label>
|
||||
</li>
|
||||
</PermissionsWidgetItem>
|
||||
<PermissionsWidgetItem
|
||||
id="1-write"
|
||||
key=".$1"
|
||||
label="write"
|
||||
mode="read"
|
||||
selected="unselected"
|
||||
>
|
||||
<li
|
||||
|
@ -423,38 +398,14 @@ exports[`Account rendering renders! 1`] = `
|
|||
<label
|
||||
className="permissions-widget--item-label"
|
||||
>
|
||||
write
|
||||
read
|
||||
</label>
|
||||
</li>
|
||||
</PermissionsWidgetItem>
|
||||
</ul>
|
||||
</section>
|
||||
</PermissionsWidgetSection>
|
||||
<PermissionsWidgetSection
|
||||
id="2"
|
||||
key=".$2"
|
||||
mode="read"
|
||||
title="buckets:telegraf"
|
||||
>
|
||||
<section
|
||||
className="permissions-widget--section"
|
||||
>
|
||||
<header
|
||||
className="permissions-widget--section-heading"
|
||||
>
|
||||
<h3
|
||||
className="permissions-widget--section-title"
|
||||
>
|
||||
buckets:telegraf
|
||||
</h3>
|
||||
</header>
|
||||
<ul
|
||||
className="permissions-widget--section-list"
|
||||
>
|
||||
<PermissionsWidgetItem
|
||||
id="2-read"
|
||||
key=".$0"
|
||||
label="read"
|
||||
id="buckets-write"
|
||||
key=".$1"
|
||||
label="write"
|
||||
mode="read"
|
||||
selected="selected"
|
||||
>
|
||||
|
@ -469,179 +420,6 @@ exports[`Account rendering renders! 1`] = `
|
|||
className="icon checkmark"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
className="permissions-widget--item-label"
|
||||
>
|
||||
read
|
||||
</label>
|
||||
</li>
|
||||
</PermissionsWidgetItem>
|
||||
<PermissionsWidgetItem
|
||||
id="2-write"
|
||||
key=".$1"
|
||||
label="write"
|
||||
mode="read"
|
||||
selected="unselected"
|
||||
>
|
||||
<li
|
||||
className="permissions-widget--item unselected"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="permissions-widget--icon"
|
||||
>
|
||||
<span
|
||||
className="icon remove"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
className="permissions-widget--item-label"
|
||||
>
|
||||
write
|
||||
</label>
|
||||
</li>
|
||||
</PermissionsWidgetItem>
|
||||
</ul>
|
||||
</section>
|
||||
</PermissionsWidgetSection>
|
||||
<PermissionsWidgetSection
|
||||
id="tasks"
|
||||
key=".$3"
|
||||
mode="read"
|
||||
title="tasks:task1"
|
||||
>
|
||||
<section
|
||||
className="permissions-widget--section"
|
||||
>
|
||||
<header
|
||||
className="permissions-widget--section-heading"
|
||||
>
|
||||
<h3
|
||||
className="permissions-widget--section-title"
|
||||
>
|
||||
tasks:task1
|
||||
</h3>
|
||||
</header>
|
||||
<ul
|
||||
className="permissions-widget--section-list"
|
||||
>
|
||||
<PermissionsWidgetItem
|
||||
id="tasks-read"
|
||||
key=".$0"
|
||||
label="read"
|
||||
mode="read"
|
||||
selected="selected"
|
||||
>
|
||||
<li
|
||||
className="permissions-widget--item selected"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="permissions-widget--icon"
|
||||
>
|
||||
<span
|
||||
className="icon checkmark"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
className="permissions-widget--item-label"
|
||||
>
|
||||
read
|
||||
</label>
|
||||
</li>
|
||||
</PermissionsWidgetItem>
|
||||
<PermissionsWidgetItem
|
||||
id="tasks-write"
|
||||
key=".$1"
|
||||
label="write"
|
||||
mode="read"
|
||||
selected="unselected"
|
||||
>
|
||||
<li
|
||||
className="permissions-widget--item unselected"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="permissions-widget--icon"
|
||||
>
|
||||
<span
|
||||
className="icon remove"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
className="permissions-widget--item-label"
|
||||
>
|
||||
write
|
||||
</label>
|
||||
</li>
|
||||
</PermissionsWidgetItem>
|
||||
</ul>
|
||||
</section>
|
||||
</PermissionsWidgetSection>
|
||||
<PermissionsWidgetSection
|
||||
id="2"
|
||||
key=".$4"
|
||||
mode="read"
|
||||
title="tasks:task1"
|
||||
>
|
||||
<section
|
||||
className="permissions-widget--section"
|
||||
>
|
||||
<header
|
||||
className="permissions-widget--section-heading"
|
||||
>
|
||||
<h3
|
||||
className="permissions-widget--section-title"
|
||||
>
|
||||
tasks:task1
|
||||
</h3>
|
||||
</header>
|
||||
<ul
|
||||
className="permissions-widget--section-list"
|
||||
>
|
||||
<PermissionsWidgetItem
|
||||
id="2-read"
|
||||
key=".$0"
|
||||
label="read"
|
||||
mode="read"
|
||||
selected="selected"
|
||||
>
|
||||
<li
|
||||
className="permissions-widget--item selected"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="permissions-widget--icon"
|
||||
>
|
||||
<span
|
||||
className="icon checkmark"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
className="permissions-widget--item-label"
|
||||
>
|
||||
read
|
||||
</label>
|
||||
</li>
|
||||
</PermissionsWidgetItem>
|
||||
<PermissionsWidgetItem
|
||||
id="2-write"
|
||||
key=".$1"
|
||||
label="write"
|
||||
mode="read"
|
||||
selected="unselected"
|
||||
>
|
||||
<li
|
||||
className="permissions-widget--item unselected"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="permissions-widget--icon"
|
||||
>
|
||||
<span
|
||||
className="icon remove"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
className="permissions-widget--item-label"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
import _ from 'lodash'
|
||||
|
||||
interface Greeting {
|
||||
text: string
|
||||
language: string
|
||||
}
|
||||
|
||||
const randomGreetings: Greeting[] = [
|
||||
{
|
||||
text: 'Greetings',
|
||||
language: 'English',
|
||||
},
|
||||
{
|
||||
text: 'Ahoy',
|
||||
language: 'Pirate',
|
||||
},
|
||||
{
|
||||
text: 'Howdy',
|
||||
language: 'Texas',
|
||||
},
|
||||
{
|
||||
text: 'Bonjour',
|
||||
language: 'French',
|
||||
},
|
||||
{
|
||||
text: 'Hola',
|
||||
language: 'Spanish',
|
||||
},
|
||||
{
|
||||
text: 'Ciao',
|
||||
language: 'Italian',
|
||||
},
|
||||
{
|
||||
text: 'Hallo',
|
||||
language: 'German',
|
||||
},
|
||||
{
|
||||
text: 'Guten Tag',
|
||||
language: 'German',
|
||||
},
|
||||
{
|
||||
text: 'Olà',
|
||||
language: 'Portuguese',
|
||||
},
|
||||
{
|
||||
text: 'Namaste',
|
||||
language: 'Hindi',
|
||||
},
|
||||
{
|
||||
text: 'Salaam',
|
||||
language: 'Farsi',
|
||||
},
|
||||
{
|
||||
text: 'Ohayo',
|
||||
language: 'Japanese',
|
||||
},
|
||||
{
|
||||
text: 'こんにちは',
|
||||
language: 'Japanese',
|
||||
},
|
||||
{
|
||||
text: 'Merhaba',
|
||||
language: 'Turkish',
|
||||
},
|
||||
{
|
||||
text: 'Szia',
|
||||
language: 'Hungarian',
|
||||
},
|
||||
{
|
||||
text: 'Jambo',
|
||||
language: 'Swahili',
|
||||
},
|
||||
{
|
||||
text: '你好',
|
||||
language: 'Chinese (Simplified)',
|
||||
},
|
||||
{
|
||||
text: 'مرحبا',
|
||||
language: 'Arabic',
|
||||
},
|
||||
{
|
||||
text: 'Բարեւ',
|
||||
language: 'Armenian',
|
||||
},
|
||||
{
|
||||
text: 'Zdravo',
|
||||
language: 'Croatian',
|
||||
},
|
||||
{
|
||||
text: 'Привет',
|
||||
language: 'Russian',
|
||||
},
|
||||
{
|
||||
text: 'Xin chào',
|
||||
language: 'Vietnamese',
|
||||
},
|
||||
{
|
||||
text: 'สวัสดี',
|
||||
language: 'Thai',
|
||||
},
|
||||
{
|
||||
text: 'สวัสดี',
|
||||
language: 'Thai',
|
||||
},
|
||||
{
|
||||
text: 'Dzień dobry',
|
||||
language: 'Polish',
|
||||
},
|
||||
{
|
||||
text: 'Hei',
|
||||
language: 'Finnish',
|
||||
},
|
||||
{
|
||||
text: 'γεια σας',
|
||||
language: 'Greek',
|
||||
},
|
||||
{
|
||||
text: '인사말',
|
||||
language: 'Korean',
|
||||
},
|
||||
{
|
||||
text: 'Salve',
|
||||
language: 'Latin',
|
||||
},
|
||||
{
|
||||
text: 'Cyfarchion',
|
||||
language: 'Welsh',
|
||||
},
|
||||
{
|
||||
text: 'Ukubingelela',
|
||||
language: 'Zulu',
|
||||
},
|
||||
{
|
||||
text: 'Beannachtaí',
|
||||
language: 'Irish',
|
||||
},
|
||||
{
|
||||
text: '01001000 01100101 01101100 01101100 01101111',
|
||||
language: 'Binary',
|
||||
},
|
||||
{
|
||||
text: '.... . .-.. .-.. ---',
|
||||
language: 'Morse Code',
|
||||
},
|
||||
{
|
||||
text: 'nuqneH',
|
||||
language: 'Klingon',
|
||||
},
|
||||
{
|
||||
text: 'Saluton',
|
||||
language: 'Esperanto',
|
||||
},
|
||||
]
|
||||
|
||||
export const generateRandomGreeting = (): Greeting => {
|
||||
return _.sample(randomGreetings)
|
||||
}
|
|
@ -6,10 +6,12 @@ import {connect} from 'react-redux'
|
|||
import 'src/me/containers/MePage.scss'
|
||||
|
||||
// Components
|
||||
import {Grid, Columns} from 'src/clockface'
|
||||
import {Page} from 'src/pageLayout'
|
||||
import Resources from 'src/me/components/Resources'
|
||||
import Header from 'src/me/components/UserPageHeader'
|
||||
import Docs from 'src/me/components/Docs'
|
||||
import GettingStarted from 'src/me/components/GettingStarted'
|
||||
|
||||
// Types
|
||||
import {MeState, AppState} from 'src/types/v2'
|
||||
|
@ -30,19 +32,25 @@ export class MePage extends PureComponent<StateProps> {
|
|||
|
||||
return (
|
||||
<Page className="user-page" titleTag="My Account">
|
||||
<Header title={`Howdy, ${me.name}!`} />
|
||||
<Header userName={me.name} />
|
||||
<Page.Contents fullWidth={false} scrollable={true}>
|
||||
<div className="col-xs-8">
|
||||
<Panel>
|
||||
<Panel.Header title="Getting Started" />
|
||||
<Panel.Body>
|
||||
<span>Put Getting Started Stuff Here</span>
|
||||
</Panel.Body>
|
||||
</Panel>
|
||||
<Docs />
|
||||
</div>
|
||||
<div className="col-xs-4">
|
||||
<Resources me={me} />
|
||||
<div className="col-xs-12">
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
<Grid.Column widthSM={Columns.Eight} widthMD={Columns.Nine}>
|
||||
<Panel>
|
||||
<Panel.Header title="Getting started with InfluxDB 2.0" />
|
||||
<Panel.Body>
|
||||
<GettingStarted />
|
||||
</Panel.Body>
|
||||
</Panel>
|
||||
<Docs />
|
||||
</Grid.Column>
|
||||
<Grid.Column widthSM={Columns.Four} widthMD={Columns.Three}>
|
||||
<Resources me={me} />
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
Getting Started Collector Graphic
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@import 'src/style/modules';
|
||||
|
||||
$collector-graphic-anim-time: 0.5s;
|
||||
|
||||
.collector-graphic--bg {
|
||||
fill: $g2-kevlar;
|
||||
transition: fill 0.25s ease;
|
||||
}
|
||||
|
||||
.collector-graphic--dot {
|
||||
fill: $g5-pepper;
|
||||
transition: fill $collector-graphic-anim-time ease;
|
||||
}
|
||||
|
||||
.collector-graphic--bucket {
|
||||
fill: $g5-pepper;
|
||||
transition: fill 0.25s ease;
|
||||
}
|
||||
|
||||
.collector-graphic--bucket-hole {
|
||||
fill: $g2-kevlar;
|
||||
transition: fill 0.25s ease;
|
||||
}
|
||||
|
||||
.collector-graphic--data {
|
||||
fill: none;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
stroke-miterlimit: 10;
|
||||
transition: all $collector-graphic-anim-time ease;
|
||||
}
|
||||
|
||||
.data-a,
|
||||
.data-b,
|
||||
.data-c,
|
||||
.data-d,
|
||||
.data-e {
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.data-a {
|
||||
stroke: $c-rainforest;
|
||||
stroke-dasharray: 146;
|
||||
stroke-dashoffset: 146;
|
||||
}
|
||||
|
||||
.data-b {
|
||||
stroke: $c-thunder;
|
||||
stroke-dasharray: 102;
|
||||
stroke-dashoffset: 102;
|
||||
}
|
||||
|
||||
.data-c {
|
||||
stroke: $c-pool;
|
||||
stroke-dasharray: 81;
|
||||
stroke-dashoffset: 81;
|
||||
}
|
||||
|
||||
.data-d {
|
||||
stroke: $c-comet;
|
||||
stroke-dasharray: 102;
|
||||
stroke-dashoffset: 102;
|
||||
}
|
||||
|
||||
.data-e {
|
||||
stroke: $c-dreamsicle;
|
||||
stroke-dasharray: 146;
|
||||
stroke-dashoffset: 146;
|
||||
}
|
||||
|
||||
@keyframes cubo-spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.collector-graphic--cubo {
|
||||
animation: cubo-spin 5s linear infinite;
|
||||
transform-origin: 161px 161.6px;
|
||||
transition: opacity $collector-graphic-anim-time ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.collector-graphic--cubo-line {
|
||||
transition: stroke 0.25s ease;
|
||||
stroke-width: 1.5px;
|
||||
stroke: $g2-kevlar;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
/* Hover State */
|
||||
.getting-started--card:hover {
|
||||
.collector-graphic--bucket {
|
||||
fill: $g13-mist;
|
||||
}
|
||||
.collector-graphic--bucket-hole {
|
||||
fill: $g9-mountain;
|
||||
}
|
||||
.collector-graphic--bg {
|
||||
fill: $g3-castle;
|
||||
}
|
||||
.dot-a {
|
||||
fill: $c-rainforest;
|
||||
}
|
||||
.dot-b {
|
||||
fill: $c-thunder;
|
||||
}
|
||||
.dot-c {
|
||||
fill: $c-pool;
|
||||
}
|
||||
.dot-d {
|
||||
fill: $c-comet;
|
||||
}
|
||||
.dot-e {
|
||||
fill: $c-dreamsicle;
|
||||
}
|
||||
.data-a,
|
||||
.data-b,
|
||||
.data-c,
|
||||
.data-d,
|
||||
.data-e {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
.collector-graphic--cubo {
|
||||
opacity: 1;
|
||||
}
|
||||
.collector-graphic--cubo-line {
|
||||
stroke: $g9-mountain;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Styles
|
||||
import 'src/me/graphics/CollectorGraphic.scss'
|
||||
|
||||
export default class GettingStarted extends PureComponent {
|
||||
public render() {
|
||||
return (
|
||||
<div className="getting-started--image collector-graphic">
|
||||
<svg
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="322px"
|
||||
height="225px"
|
||||
viewBox="0 0 322 225"
|
||||
>
|
||||
<g id="Bucket">
|
||||
<path
|
||||
id="BG"
|
||||
className="collector-graphic--bg"
|
||||
d="M161,199c-14.1,0-29.2-3.8-29.8-14.4l-6.9-51.3v-0.5c0-13.1,23-15.1,36.7-15.1s36.7,2,36.7,15.1v0.5
|
||||
l-6.9,51.3C190.2,195.2,175.1,199,161,199z"
|
||||
/>
|
||||
<path
|
||||
id="BucketExterior"
|
||||
className="collector-graphic--bucket"
|
||||
d="M132.3,132.8c0-3.9,12.8-7.1,28.7-7.1s28.7,3.2,28.7,7.1l-6.9,51.1
|
||||
c0,3.9-9.7,7.1-21.8,7.1c-12.1,0-21.8-3.1-21.8-7.1L132.3,132.8z"
|
||||
/>
|
||||
<ellipse
|
||||
id="BucketHole"
|
||||
className="collector-graphic--bucket-hole"
|
||||
cx="160.8"
|
||||
cy="132.8"
|
||||
rx="25.1"
|
||||
ry="4.7"
|
||||
/>
|
||||
</g>
|
||||
<g id="Blocks">
|
||||
<path
|
||||
className="collector-graphic--bg"
|
||||
d="M178.2,66.5c0,1.1-0.9,2-2,2h-30.5c-1.1,0-2-0.9-2-2V36c0-1.1,0.9-2,2-2h30.5c1.1,0,2,0.9,2,2V66.5z"
|
||||
/>
|
||||
<path
|
||||
className="collector-graphic--bg"
|
||||
d="M121.4,66.5c0,1.1-0.9,2-2,2H88.9c-1.1,0-2-0.9-2-2V36c0-1.1,0.9-2,2-2h30.5c1.1,0,2,0.9,2,2V66.5z"
|
||||
/>
|
||||
<path
|
||||
className="collector-graphic--bg"
|
||||
d="M64.5,66.5c0,1.1-0.9,2-2,2H32c-1.1,0-2-0.9-2-2V36c0-1.1,0.9-2,2-2h30.5c1.1,0,2,0.9,2,2V66.5z"
|
||||
/>
|
||||
<path
|
||||
className="collector-graphic--bg"
|
||||
d="M235.1,66.5c0,1.1-0.9,2-2,2h-30.5c-1.1,0-2-0.9-2-2V36c0-1.1,0.9-2,2-2h30.5c1.1,0,2,0.9,2,2V66.5z"
|
||||
/>
|
||||
<path
|
||||
className="collector-graphic--bg"
|
||||
d="M292,66.5c0,1.1-0.9,2-2,2h-30.5c-1.1,0-2-0.9-2-2V36c0-1.1,0.9-2,2-2H290c1.1,0,2,0.9,2,2V66.5z"
|
||||
/>
|
||||
</g>
|
||||
<g id="Lines">
|
||||
<path
|
||||
id="LineE"
|
||||
className="collector-graphic--data data-e"
|
||||
d="M274.8,58.3c0,63-105.5,35.5-105.5,81.3"
|
||||
/>
|
||||
<path
|
||||
id="LineD"
|
||||
className="collector-graphic--data data-d"
|
||||
d="M217.9,58.3c0,10.2-9.4,25.8-23.6,34.5s-29.5,24.4-29.5,46.7"
|
||||
/>
|
||||
<line
|
||||
id="LineC"
|
||||
className="collector-graphic--data data-c"
|
||||
x1="161"
|
||||
y1="58.3"
|
||||
x2="161"
|
||||
y2="139.5"
|
||||
/>
|
||||
<path
|
||||
id="LineB"
|
||||
className="collector-graphic--data data-b"
|
||||
d="M104.1,58.3c0,10.2,9.4,25.8,23.6,34.5s29.5,24.4,29.5,46.7"
|
||||
/>
|
||||
<path
|
||||
id="LineA"
|
||||
className="collector-graphic--data data-a"
|
||||
d="M47.2,58.3c0,63,105.5,35.5,105.5,81.3"
|
||||
/>
|
||||
</g>
|
||||
<g id="Dots">
|
||||
<circle
|
||||
id="DotE"
|
||||
className="collector-graphic--dot dot-e"
|
||||
cx="274.8"
|
||||
cy="51.3"
|
||||
r="7"
|
||||
/>
|
||||
<circle
|
||||
id="DotD"
|
||||
className="collector-graphic--dot dot-d"
|
||||
cx="217.9"
|
||||
cy="51.3"
|
||||
r="7"
|
||||
/>
|
||||
<circle
|
||||
id="DotC"
|
||||
className="collector-graphic--dot dot-c"
|
||||
cx="161"
|
||||
cy="51.3"
|
||||
r="7"
|
||||
/>
|
||||
<circle
|
||||
id="DotB"
|
||||
className="collector-graphic--dot dot-b"
|
||||
cx="104.1"
|
||||
cy="51.3"
|
||||
r="7"
|
||||
/>
|
||||
<circle
|
||||
id="DotA"
|
||||
className="collector-graphic--dot dot-a"
|
||||
cx="47.2"
|
||||
cy="51.3"
|
||||
r="7"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
id="BucketMask"
|
||||
className="collector-graphic--bucket"
|
||||
d="M176.2,126.8v2.3c5.9,0.9,9.7,2.2,9.7,3.7c0,2.6-11.2,4.7-25.1,4.7s-25.1-2.1-25.1-4.7
|
||||
c0-1.5,3.6-2.8,9.2-3.6V127c-7.7,1.3-12.7,3.4-12.7,5.9l6.9,51.1c0,3.9,9.7,7.1,21.8,7.1s21.8-3.1,21.8-7.1l6.9-51.1
|
||||
C189.7,130.3,184.3,128.1,176.2,126.8z"
|
||||
/>
|
||||
<g id="Cubo" className="collector-graphic--cubo">
|
||||
<polygon
|
||||
className="collector-graphic--cubo-line"
|
||||
points="166.5,150.9 155.1,150.9 149.4,160.8 155.1,170.7 166.5,170.7 172.2,160.8 "
|
||||
/>
|
||||
<polygon
|
||||
className="collector-graphic--cubo-line"
|
||||
points="155.1,164.1 160.8,154.2 166.5,164.1 "
|
||||
/>
|
||||
<polyline
|
||||
className="collector-graphic--cubo-line"
|
||||
points="155.1,150.9 160.8,154.2 166.5,150.9 "
|
||||
/>
|
||||
<polyline
|
||||
className="collector-graphic--cubo-line"
|
||||
points="172.2,160.8 166.5,164.1 166.5,170.7 "
|
||||
/>
|
||||
<polyline
|
||||
className="collector-graphic--cubo-line"
|
||||
points="155.1,170.7 155.1,164.1 149.4,160.8 "
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
Getting Started Dashboard Graphic
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@import 'src/style/modules';
|
||||
|
||||
$dashboarding-graphic-anim-time: 0.5s;
|
||||
|
||||
.dashboarding-graphic--bg {
|
||||
transition: fill 0.25s ease;
|
||||
fill: $g2-kevlar;
|
||||
}
|
||||
|
||||
.dashboarding-graphic--cell {
|
||||
fill: $g5-pepper;
|
||||
transition: fill 0.25s ease;
|
||||
}
|
||||
|
||||
.dashboarding-graphic--single-stat {
|
||||
fill: $g5-pepper;
|
||||
transition: fill $dashboarding-graphic-anim-time ease;
|
||||
}
|
||||
|
||||
.dashboarding-graphic--axes {
|
||||
stroke-width: 1.5px;
|
||||
stroke: $g5-pepper;
|
||||
fill: transparent;
|
||||
transition: fill $dashboarding-graphic-anim-time ease, stroke $dashboarding-graphic-anim-time ease;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
|
||||
.dashboarding-graphic--line {
|
||||
fill: none;
|
||||
stroke-width: 1.5px;
|
||||
stroke: $g5-pepper;
|
||||
transition: stroke $dashboarding-graphic-anim-time ease;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
|
||||
.line-a,
|
||||
.line-b,
|
||||
.line-c,
|
||||
.line-d {
|
||||
transition: all $dashboarding-graphic-anim-time ease;
|
||||
}
|
||||
|
||||
.line-a {
|
||||
stroke-dasharray: 122;
|
||||
stroke-dashoffset: 122;
|
||||
}
|
||||
|
||||
.line-b {
|
||||
stroke-dasharray: 161;
|
||||
stroke-dashoffset: 161;
|
||||
}
|
||||
|
||||
.line-c {
|
||||
stroke-dasharray: 102;
|
||||
stroke-dashoffset: 102;
|
||||
}
|
||||
|
||||
.line-d {
|
||||
stroke-dasharray: 99;
|
||||
stroke-dashoffset: 99;
|
||||
}
|
||||
|
||||
.dashboarding-graphic--bar {
|
||||
fill: $g5-pepper;
|
||||
transition: all $dashboarding-graphic-anim-time ease;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/* Hover State */
|
||||
.getting-started--card:hover {
|
||||
.dashboarding-graphic--bg {
|
||||
fill: $g3-castle;
|
||||
}
|
||||
.dashboarding-graphic--cell {
|
||||
fill: $g6-smoke;
|
||||
}
|
||||
.single-stat-a {
|
||||
fill: $c-pool;
|
||||
}
|
||||
.single-stat-b {
|
||||
fill: $c-dreamsicle;
|
||||
}
|
||||
.single-stat-c {
|
||||
fill: $c-honeydew;
|
||||
}
|
||||
.single-stat-d {
|
||||
fill: $c-comet;
|
||||
}
|
||||
.table-a {
|
||||
fill: $c-pool;
|
||||
}
|
||||
.table-b {
|
||||
fill: $c-comet;
|
||||
}
|
||||
.line-a,
|
||||
.line-b,
|
||||
.line-c,
|
||||
.line-d {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
.line-a {
|
||||
stroke: $c-honeydew;
|
||||
}
|
||||
.line-b {
|
||||
stroke: $c-pool;
|
||||
}
|
||||
.line-c {
|
||||
stroke: $c-comet;
|
||||
}
|
||||
.line-d {
|
||||
stroke: $c-thunder;
|
||||
}
|
||||
.dashboarding-graphic--axes {
|
||||
stroke: $g7-graphite;
|
||||
}
|
||||
.dashboarding-graphic--bar {
|
||||
fill: $c-pool;
|
||||
}
|
||||
.bar-a {
|
||||
height: 15.2px;
|
||||
}
|
||||
.bar-b {
|
||||
height: 32.2px;
|
||||
}
|
||||
.bar-c {
|
||||
height: 25.8px;
|
||||
}
|
||||
.bar-d {
|
||||
height: 4px;
|
||||
}
|
||||
.bar-e {
|
||||
height: 2px;
|
||||
}
|
||||
.bar-f {
|
||||
height: 7.6px;
|
||||
}
|
||||
.bar-g {
|
||||
height: 4px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,379 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Styles
|
||||
import 'src/me/graphics/DashboardingGraphic.scss'
|
||||
|
||||
export default class GettingStarted extends PureComponent {
|
||||
public render() {
|
||||
return (
|
||||
<div className="getting-started--image dashboarding-graphic">
|
||||
<svg
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="322px"
|
||||
height="225px"
|
||||
viewBox="0 0 322 225"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
id="Background"
|
||||
className="dashboarding-graphic--bg"
|
||||
d="M291,30.5H31c-2.2,0-4,1.8-4,4v156c0,2.2,1.8,4,4,4h260c2.2,0,4-1.8,4-4v-156
|
||||
C295,32.3,293.2,30.5,291,30.5z"
|
||||
/>
|
||||
<g id="Cells">
|
||||
<path
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M162,41.5c0-1.7,1.3-3,3-3h55.5c1.7,0,3,1.3,3,3v23c0,1.7-1.3,3-3,3H165c-1.7,0-3-1.3-3-3V41.5z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M98.5,41.4c0.1-1.6,1.4-2.9,3-2.9H157c1.7,0,3,1.3,3,3v23c0,1.7-1.3,3-3,3h-55.5c-1.6,0-2.9-1.3-3-2.9
|
||||
c0,0,0-0.1,0-0.1v-23C98.5,41.5,98.5,41.4,98.5,41.4z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M35,41.5c0-1.7,1.3-3,3-3h55.5c1.6,0,2.9,1.3,3,2.9c0,0,0,0.1,0,0.1v23c0,0,0,0.1,0,0.1
|
||||
c-0.1,1.6-1.4,2.9-3,2.9H38c-1.7,0-3-1.3-3-3V41.5z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M35,72.5c0-1.7,1.3-3,3-3h55.5h8H157c1.7,0,3,1.3,3,3V132c0,1.7-1.3,3-3,3h-33h-8H38c-1.7,0-3-1.3-3-3V72.5z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M119,183.6c-0.1,1.6-1.4,2.9-3,2.9H38c-1.7,0-3-1.3-3-3V140c0-1.7,1.3-3,3-3h78c1.6,0,2.9,1.3,3,2.9
|
||||
c0,0,0,0.1,0,0.1v43.5C119,183.5,119,183.6,119,183.6z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M201,183.6c-0.1,1.6-1.4,2.9-3,2.9h-74c-1.6,0-2.9-1.3-3-2.9c0,0,0-0.1,0-0.1V140c0,0,0-0.1,0-0.1
|
||||
c0.1-1.6,1.4-2.9,3-2.9h33h8h33c1.6,0,2.9,1.3,3,2.9c0,0,0,0.1,0,0.1v43.5C201,183.5,201,183.6,201,183.6z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M287,183.5c0,1.7-1.3,3-3,3h-78c-1.6,0-2.9-1.3-3-2.9c0,0,0-0.1,0-0.1V140c0,0,0-0.1,0-0.1
|
||||
c0.1-1.6,1.4-2.9,3-2.9h78c1.7,0,3,1.3,3,3V183.5z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M287,64.5c0,1.7-1.3,3-3,3h-55.5c-1.7,0-3-1.3-3-3v-23c0-1.7,1.3-3,3-3H284c1.7,0,3,1.3,3,3V64.5z"
|
||||
/>
|
||||
<path
|
||||
id="Cell"
|
||||
className="dashboarding-graphic--cell"
|
||||
d="M287,132c0,1.7-1.3,3-3,3h-78h-8h-33c-1.7,0-3-1.3-3-3V72.5c0-1.7,1.3-3,3-3h0h55.5h8H284
|
||||
c1.7,0,3,1.3,3,3V132z"
|
||||
/>
|
||||
</g>
|
||||
<g id="Single_Stat_4392">
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-a"
|
||||
d="M57.8,54.1H59V55h-1.2v2h-1.1v-2h-3.9v-0.6l3.8-5.9h1.2V54.1z M54.1,54.1h2.7V50l-0.1,0.2L54.1,54.1z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-a"
|
||||
d="M61.5,52.2h0.8c0.5,0,0.9-0.1,1.2-0.4s0.4-0.6,0.4-1.1c0-1-0.5-1.5-1.5-1.5c-0.5,0-0.8,0.1-1.1,0.4
|
||||
S61,50.3,61,50.7h-1.1c0-0.7,0.2-1.2,0.7-1.7s1.1-0.7,1.9-0.7c0.8,0,1.4,0.2,1.9,0.6s0.7,1,0.7,1.8c0,0.4-0.1,0.7-0.4,1.1
|
||||
s-0.6,0.6-1,0.8c0.5,0.1,0.8,0.4,1.1,0.7s0.4,0.8,0.4,1.3c0,0.8-0.2,1.4-0.8,1.8s-1.2,0.7-2,0.7s-1.5-0.2-2-0.7s-0.8-1-0.8-1.7
|
||||
h1.1c0,0.4,0.1,0.8,0.4,1.1s0.7,0.4,1.2,0.4c0.5,0,0.9-0.1,1.2-0.4s0.4-0.7,0.4-1.2c0-0.5-0.2-0.9-0.5-1.1s-0.7-0.4-1.3-0.4h-0.8
|
||||
V52.2z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-a"
|
||||
d="M70.9,53.2c-0.2,0.3-0.5,0.5-0.8,0.7s-0.7,0.2-1,0.2c-0.5,0-0.9-0.1-1.3-0.4s-0.6-0.6-0.8-1s-0.3-0.9-0.3-1.5
|
||||
c0-0.6,0.1-1.1,0.3-1.5s0.5-0.8,0.9-1s0.9-0.4,1.4-0.4c0.8,0,1.5,0.3,2,0.9s0.7,1.5,0.7,2.6v0.3c0,1.7-0.3,2.9-1,3.6
|
||||
S69.3,57,68,57h-0.2v-0.9H68c0.9,0,1.6-0.2,2.1-0.7S70.8,54.2,70.9,53.2z M69.2,53.2c0.4,0,0.7-0.1,1-0.3s0.5-0.5,0.7-0.8v-0.4
|
||||
c0-0.7-0.2-1.3-0.5-1.7s-0.7-0.7-1.2-0.7c-0.5,0-0.9,0.2-1.1,0.5s-0.4,0.8-0.4,1.4c0,0.6,0.1,1.1,0.4,1.4S68.7,53.2,69.2,53.2z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-a"
|
||||
d="M79,57h-5.6v-0.8l3-3.3c0.4-0.5,0.7-0.9,0.9-1.2s0.2-0.6,0.2-1c0-0.4-0.1-0.8-0.4-1.1s-0.6-0.4-1.1-0.4
|
||||
c-0.5,0-1,0.2-1.3,0.5s-0.4,0.7-0.4,1.3h-1.1c0-0.8,0.3-1.4,0.8-1.9s1.2-0.7,2-0.7c0.8,0,1.4,0.2,1.9,0.6s0.7,1,0.7,1.7
|
||||
c0,0.8-0.5,1.8-1.6,3l-2.3,2.5H79V57z"
|
||||
/>
|
||||
</g>
|
||||
<g id="Line_Graph_A">
|
||||
<polyline
|
||||
className="dashboarding-graphic--line line-a"
|
||||
points="40,121.8 54.4,121.8 68.8,115.5 83.1,118.6 97.5,109.8 111.9,114.2 126.2,109.8 140.6,109.8
|
||||
155,117.2 "
|
||||
/>
|
||||
<polyline
|
||||
className="dashboarding-graphic--line line-b"
|
||||
points="40,118.2 54.4,118.2 68.8,104.8 83.1,74.5 97.5,99.5 111.9,92 126.2,103.8 140.6,105.5 155,109.8
|
||||
"
|
||||
/>
|
||||
<polyline
|
||||
className="dashboarding-graphic--axes"
|
||||
points="40,74.5 40,130 155,130 "
|
||||
/>
|
||||
</g>
|
||||
<g id="Single_Stat_99.5">
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-b"
|
||||
d="M245.1,53.2c-0.2,0.3-0.5,0.5-0.8,0.7s-0.7,0.2-1,0.2c-0.5,0-0.9-0.1-1.3-0.4s-0.6-0.6-0.8-1
|
||||
s-0.3-0.9-0.3-1.5c0-0.6,0.1-1.1,0.3-1.5s0.5-0.8,0.9-1s0.9-0.4,1.4-0.4c0.8,0,1.5,0.3,2,0.9s0.7,1.5,0.7,2.6v0.3
|
||||
c0,1.7-0.3,2.9-1,3.6s-1.6,1.2-3,1.2H242v-0.9h0.2c0.9,0,1.6-0.2,2.1-0.7S245,54.2,245.1,53.2z M243.4,53.2c0.4,0,0.7-0.1,1-0.3
|
||||
s0.5-0.5,0.7-0.8v-0.4c0-0.7-0.2-1.3-0.5-1.7s-0.7-0.7-1.2-0.7c-0.5,0-0.9,0.2-1.1,0.5s-0.4,0.8-0.4,1.4c0,0.6,0.1,1.1,0.4,1.4
|
||||
S242.9,53.2,243.4,53.2z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-b"
|
||||
d="M251.8,53.2c-0.2,0.3-0.5,0.5-0.8,0.7s-0.7,0.2-1,0.2c-0.5,0-0.9-0.1-1.3-0.4s-0.6-0.6-0.8-1
|
||||
s-0.3-0.9-0.3-1.5c0-0.6,0.1-1.1,0.3-1.5s0.5-0.8,0.9-1s0.9-0.4,1.4-0.4c0.8,0,1.5,0.3,2,0.9s0.7,1.5,0.7,2.6v0.3
|
||||
c0,1.7-0.3,2.9-1,3.6s-1.6,1.2-3,1.2h-0.2v-0.9h0.2c0.9,0,1.6-0.2,2.1-0.7S251.7,54.2,251.8,53.2z M250.1,53.2
|
||||
c0.4,0,0.7-0.1,1-0.3s0.5-0.5,0.7-0.8v-0.4c0-0.7-0.2-1.3-0.5-1.7s-0.7-0.7-1.2-0.7c-0.5,0-0.9,0.2-1.1,0.5s-0.4,0.8-0.4,1.4
|
||||
c0,0.6,0.1,1.1,0.4,1.4S249.7,53.2,250.1,53.2z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-b"
|
||||
d="M254.5,56.4c0-0.2,0.1-0.3,0.2-0.5s0.3-0.2,0.5-0.2s0.4,0.1,0.5,0.2s0.2,0.3,0.2,0.5c0,0.2-0.1,0.3-0.2,0.5
|
||||
s-0.3,0.2-0.5,0.2s-0.4-0.1-0.5-0.2S254.5,56.6,254.5,56.4z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-b"
|
||||
d="M258,52.7l0.4-4.3h4.4v1h-3.5l-0.3,2.3c0.4-0.2,0.9-0.4,1.4-0.4c0.8,0,1.4,0.3,1.9,0.8s0.7,1.2,0.7,2.1
|
||||
c0,0.9-0.2,1.6-0.7,2.1s-1.1,0.8-2,0.8c-0.8,0-1.4-0.2-1.8-0.6s-0.7-1-0.8-1.7h1c0.1,0.5,0.2,0.9,0.5,1.1s0.7,0.4,1.1,0.4
|
||||
c0.5,0,0.9-0.2,1.2-0.5s0.4-0.8,0.4-1.4c0-0.6-0.2-1-0.5-1.4s-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.1-1.1,0.3l-0.3,0.2L258,52.7z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-b"
|
||||
d="M264.2,50.1c0-0.5,0.2-0.9,0.5-1.3s0.7-0.5,1.3-0.5c0.5,0,0.9,0.2,1.3,0.5s0.5,0.8,0.5,1.3v0.4
|
||||
c0,0.5-0.2,0.9-0.5,1.3s-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.3-0.5s-0.5-0.8-0.5-1.3V50.1z M265,50.6c0,0.3,0.1,0.6,0.3,0.8
|
||||
s0.4,0.3,0.7,0.3c0.3,0,0.5-0.1,0.7-0.3s0.3-0.5,0.3-0.8v-0.4c0-0.3-0.1-0.6-0.3-0.8c-0.2-0.2-0.4-0.3-0.7-0.3s-0.5,0.1-0.7,0.3
|
||||
c-0.2,0.2-0.3,0.5-0.3,0.8V50.6z M266.2,56.4l-0.6-0.4l4.2-6.7l0.6,0.4L266.2,56.4z M268.3,54.9c0-0.5,0.2-0.9,0.5-1.3
|
||||
s0.7-0.5,1.3-0.5s0.9,0.2,1.3,0.5s0.5,0.8,0.5,1.3v0.4c0,0.5-0.2,0.9-0.5,1.3s-0.7,0.5-1.3,0.5s-0.9-0.2-1.3-0.5s-0.5-0.8-0.5-1.3
|
||||
V54.9z M269.1,55.4c0,0.3,0.1,0.6,0.3,0.8s0.4,0.3,0.7,0.3c0.3,0,0.5-0.1,0.7-0.3s0.3-0.5,0.3-0.8v-0.4c0-0.3-0.1-0.6-0.3-0.8
|
||||
c-0.2-0.2-0.4-0.3-0.7-0.3c-0.3,0-0.5,0.1-0.7,0.3c-0.2,0.2-0.3,0.5-0.3,0.8V55.4z"
|
||||
/>
|
||||
</g>
|
||||
<g id="Table">
|
||||
<rect
|
||||
x="167"
|
||||
y="74.5"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="115"
|
||||
height="55.5"
|
||||
/>
|
||||
<rect
|
||||
x="167"
|
||||
y="74.5"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="23"
|
||||
height="55.5"
|
||||
/>
|
||||
<rect
|
||||
x="190"
|
||||
y="74.5"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="23"
|
||||
height="55.5"
|
||||
/>
|
||||
<rect
|
||||
x="213"
|
||||
y="74.5"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="23"
|
||||
height="55.5"
|
||||
/>
|
||||
<rect
|
||||
x="236"
|
||||
y="74.5"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="23"
|
||||
height="55.5"
|
||||
/>
|
||||
<rect
|
||||
x="259"
|
||||
y="74.5"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="23"
|
||||
height="55.5"
|
||||
/>
|
||||
<rect
|
||||
x="167"
|
||||
y="74.5"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="115"
|
||||
height="7.9"
|
||||
/>
|
||||
<rect
|
||||
x="167"
|
||||
y="82.4"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="115"
|
||||
height="7.9"
|
||||
/>
|
||||
<rect
|
||||
x="167"
|
||||
y="90.4"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="115"
|
||||
height="7.9"
|
||||
/>
|
||||
<rect
|
||||
x="167"
|
||||
y="98.3"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="115"
|
||||
height="7.9"
|
||||
/>
|
||||
<rect
|
||||
x="167"
|
||||
y="106.2"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="115"
|
||||
height="7.9"
|
||||
/>
|
||||
<rect
|
||||
x="167"
|
||||
y="114.1"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="115"
|
||||
height="7.9"
|
||||
/>
|
||||
<rect
|
||||
x="167"
|
||||
y="122.1"
|
||||
className="dashboarding-graphic--axes"
|
||||
width="115"
|
||||
height="7.9"
|
||||
/>
|
||||
<rect
|
||||
id="Highlight_Blue"
|
||||
x="190"
|
||||
y="82.4"
|
||||
className="dashboarding-graphic--axes table-a"
|
||||
width="23"
|
||||
height="7.9"
|
||||
/>
|
||||
<rect
|
||||
id="Highlight_Purple"
|
||||
x="236"
|
||||
y="106.2"
|
||||
className="dashboarding-graphic--axes table-b"
|
||||
width="23"
|
||||
height="7.9"
|
||||
/>
|
||||
</g>
|
||||
<g id="Line_Graph_B">
|
||||
<polyline
|
||||
className="dashboarding-graphic--line line-c"
|
||||
points="39.5,167.8 48.8,167.8 58.1,157 67.4,162.4 76.8,147 86.1,154.8 95.4,147 104.7,147 114,160 "
|
||||
/>
|
||||
<polyline
|
||||
className="dashboarding-graphic--axes"
|
||||
points="39.5,142 39.5,181.5 114,181.5 "
|
||||
/>
|
||||
</g>
|
||||
<g id="Bar_Chart_1_">
|
||||
<polyline
|
||||
className="dashboarding-graphic--axes"
|
||||
points="126,142 126,181.5 196,181.5 "
|
||||
/>
|
||||
<g id="Bar_Chart">
|
||||
<rect
|
||||
x="130"
|
||||
y="166.3"
|
||||
className="dashboarding-graphic--bar bar-a"
|
||||
width="6.3"
|
||||
height="15.2"
|
||||
transform="scale(1,-1) translate(0,-347.2)"
|
||||
/>
|
||||
<rect
|
||||
x="139.1"
|
||||
y="149.3"
|
||||
className="dashboarding-graphic--bar bar-b"
|
||||
width="6.3"
|
||||
height="32.2"
|
||||
transform="scale(1,-1) translate(0,-330)"
|
||||
/>
|
||||
<rect
|
||||
x="148.3"
|
||||
y="155.7"
|
||||
className="dashboarding-graphic--bar bar-c"
|
||||
width="6.3"
|
||||
height="25.8"
|
||||
transform="scale(1,-1) translate(0,-336.5)"
|
||||
/>
|
||||
<rect
|
||||
x="157.4"
|
||||
y="177.5"
|
||||
className="dashboarding-graphic--bar bar-d"
|
||||
width="6.3"
|
||||
height="4"
|
||||
transform="scale(1,-1) translate(0,-358.5)"
|
||||
/>
|
||||
<rect
|
||||
x="166.5"
|
||||
y="179.5"
|
||||
className="dashboarding-graphic--bar bar-e"
|
||||
width="6.3"
|
||||
height="2"
|
||||
transform="scale(1,-1) translate(0,-360.5)"
|
||||
/>
|
||||
<rect
|
||||
x="175.6"
|
||||
y="173.9"
|
||||
className="dashboarding-graphic--bar bar-f"
|
||||
width="6.3"
|
||||
height="7.6"
|
||||
transform="scale(1,-1) translate(0,-355)"
|
||||
/>
|
||||
<rect
|
||||
x="184.7"
|
||||
y="177.5"
|
||||
className="dashboarding-graphic--bar bar-g"
|
||||
width="6.3"
|
||||
height="4"
|
||||
transform="scale(1,-1) translate(0,-358.5)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Line_Graph_C">
|
||||
<polyline
|
||||
className="dashboarding-graphic--line line-d"
|
||||
points="207.7,161 217.1,173.9 226.4,176.2 235.7,163.7 245,167.8 254.3,152.9 264.1,145 272.9,148
|
||||
282.3,148 "
|
||||
/>
|
||||
<polyline
|
||||
className="dashboarding-graphic--axes"
|
||||
points="207.7,142 207.7,181.5 282.3,181.5 "
|
||||
/>
|
||||
</g>
|
||||
<g id="Single_Stat_4">
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-c"
|
||||
d="M194.7,53.9h1.2v0.9h-1.2v2h-1.1v-2h-3.9v-0.6l3.8-5.9h1.2V53.9z M190.9,53.9h2.7v-4.2l-0.1,0.2L190.9,53.9z
|
||||
"
|
||||
/>
|
||||
</g>
|
||||
<g id="Single_Stat_ABC">
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-d"
|
||||
d="M123.4,54.8h-3.6L119,57h-1.2l3.3-8.5h1l3.3,8.5h-1.2L123.4,54.8z M120.2,53.8h2.9l-1.5-4L120.2,53.8z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-d"
|
||||
d="M126.5,57v-8.5h2.8c0.9,0,1.6,0.2,2.1,0.6s0.7,0.9,0.7,1.7c0,0.4-0.1,0.8-0.3,1.1s-0.5,0.5-0.9,0.7
|
||||
c0.5,0.1,0.8,0.4,1.1,0.7s0.4,0.8,0.4,1.3c0,0.8-0.2,1.4-0.7,1.8s-1.2,0.7-2.1,0.7H126.5z M127.6,52.1h1.7c0.5,0,0.9-0.1,1.2-0.4
|
||||
c0.3-0.2,0.4-0.6,0.4-1c0-0.5-0.1-0.8-0.4-1c-0.3-0.2-0.7-0.3-1.2-0.3h-1.7V52.1z M127.6,53v3.1h1.9c0.5,0,0.9-0.1,1.2-0.4
|
||||
s0.5-0.6,0.5-1.1c0-1-0.6-1.5-1.7-1.5H127.6z"
|
||||
/>
|
||||
<path
|
||||
className="dashboarding-graphic--single-stat single-stat-d"
|
||||
d="M140.3,54.3c-0.1,0.9-0.4,1.6-1,2.1s-1.3,0.7-2.2,0.7c-1,0-1.8-0.4-2.4-1.1s-0.9-1.7-0.9-2.9v-0.8
|
||||
c0-0.8,0.1-1.5,0.4-2.1s0.7-1.1,1.2-1.4s1.1-0.5,1.8-0.5c0.9,0,1.6,0.3,2.2,0.8s0.9,1.2,1,2.1h-1.1c-0.1-0.7-0.3-1.2-0.6-1.5
|
||||
s-0.8-0.5-1.4-0.5c-0.7,0-1.3,0.3-1.7,0.8c-0.4,0.5-0.6,1.3-0.6,2.3v0.8c0,0.9,0.2,1.7,0.6,2.2s0.9,0.8,1.6,0.8
|
||||
c0.6,0,1.1-0.1,1.4-0.4s0.6-0.8,0.7-1.5H140.3z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
Getting Started Explore Graphic
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@import 'src/style/modules';
|
||||
|
||||
$explore-graphic-anim-time: 0.5s;
|
||||
|
||||
.explore-graphic--bg {
|
||||
transition: fill 0.25s ease;
|
||||
fill: $g2-kevlar;
|
||||
}
|
||||
|
||||
.explore-graphic--hex {
|
||||
fill: $g5-pepper;
|
||||
transition: fill 0.25s ease;
|
||||
}
|
||||
|
||||
.hex-a,
|
||||
.hex-b {
|
||||
transition: fill $explore-graphic-anim-time ease;
|
||||
}
|
||||
|
||||
.explore-graphic--text {
|
||||
stroke: transparent;
|
||||
fill: none;
|
||||
transition: stroke $explore-graphic-anim-time ease;
|
||||
}
|
||||
|
||||
.explore-graphic--diagnostic {
|
||||
fill: transparent;
|
||||
transition: fill $explore-graphic-anim-time ease;
|
||||
}
|
||||
|
||||
.explore-graphic--flows {
|
||||
opacity: 0;
|
||||
transition: opacity $explore-graphic-anim-time ease;
|
||||
}
|
||||
|
||||
@keyframes flow {
|
||||
0% {
|
||||
stroke-dashoffset: 0px;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.explore-graphic--flow {
|
||||
fill: none;
|
||||
stroke-width: 2px;
|
||||
stroke-dasharray: 4px;
|
||||
stroke-dashoffset: 0px;
|
||||
animation: flow 1s linear infinite;
|
||||
}
|
||||
|
||||
.flow-a {
|
||||
stroke: $c-honeydew;
|
||||
}
|
||||
|
||||
.flow-b {
|
||||
stroke: $c-pool;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
|
||||
|
||||
/* Hover State */
|
||||
.getting-started--card:hover {
|
||||
.explore-graphic--bg {
|
||||
fill: $g3-castle;
|
||||
}
|
||||
.explore-graphic--hex {
|
||||
fill: $g6-smoke;
|
||||
}
|
||||
.explore-graphic--text {
|
||||
stroke: $g13-mist;
|
||||
}
|
||||
.hex-a,
|
||||
.diagnostic-a {
|
||||
fill: $c-pool;
|
||||
}
|
||||
.hex-b,
|
||||
.diagnostic-b {
|
||||
fill: $c-honeydew;
|
||||
}
|
||||
.explore-graphic--flows {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Styles
|
||||
import 'src/me/graphics/ExploreGraphic.scss'
|
||||
|
||||
export default class GettingStarted extends PureComponent {
|
||||
public render() {
|
||||
return (
|
||||
<div className="getting-started--image explore-graphic">
|
||||
<svg
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="322px"
|
||||
height="225px"
|
||||
viewBox="0 0 322 225"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
id="Background_2_"
|
||||
className="explore-graphic--bg"
|
||||
d="M302,34.3l-8.8-15.2c-2-3.4-6-5.7-9.9-5.7h-17.6c-4,0-7.9,2.3-9.9,5.7l-7.5,13h-12.4
|
||||
l-7.5-13c-2-3.4-6-5.7-9.9-5.7h-17.6c-4,0-7.9,2.3-9.9,5.7l-7.5,13h-15c-4,0-7.9,2.3-9.9,5.7l-7.5,13h-12.4l-7.5-13
|
||||
c-2-3.4-6-5.7-9.9-5.7h-15l-7.5-13c-2-3.4-6-5.7-9.9-5.7H71.2c-4,0-7.9,2.3-9.9,5.7l-7.5,13h-15c-4,0-7.9,2.3-9.9,5.7L20,53
|
||||
c-2,3.4-2,8,0,11.5l7.5,13l-7.5,13c-2,3.4-2,8,0,11.5l7.5,13l-7.5,13c-2,3.4-2,8,0,11.5l8.8,15.2c2,3.4,6,5.7,9.9,5.7h15l7.5,13
|
||||
c2,3.4,6,5.7,9.9,5.7h17.6c4,0,7.9-2.3,9.9-5.7l7.5-13h12.4l6.2,10.7l-7.5,13c-2,3.4-2,8,0,11.5l8.8,15.2c2,3.4,6,5.7,9.9,5.7h17.6
|
||||
c4,0,7.9-2.3,9.9-5.7l7.5-13h12.4l7.5,13c2,3.4,6,5.7,9.9,5.7h17.6c4,0,7.9-2.3,9.9-5.7l8.8-15.2c2-3.4,2-8,0-11.5l-7.5-13
|
||||
l6.2-10.7h15c4,0,7.9-2.3,9.9-5.7l8.8-15.2c2-3.4,2-8,0-11.5l-7.5-13l7.5-13c2-3.4,2-8,0-11.5l-7.5-13l6.2-10.7h15
|
||||
c4,0,7.9-2.3,9.9-5.7l8.8-15.2C303.9,42.4,303.9,37.7,302,34.3z"
|
||||
/>
|
||||
<g id="Hexes">
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M200.8,59.3h17.6c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2c0.5,0.8,0.5,2.2,0,3L221,94.2c-0.5,0.8-1.6,1.5-2.6,1.5
|
||||
h-17.6c-0.9,0-2.1-0.7-2.6-1.5L189.4,79c-0.5-0.8-0.5-2.2,0-3l8.8-15.2C198.7,59.9,199.9,59.3,200.8,59.3z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M157,57.3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5H186c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2c0.5,0.8,0.5,2.2,0,3
|
||||
l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6c-0.9,0-2.1-0.7-2.6-1.5L157,60.2C156.6,59.4,156.6,58.1,157,57.3z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M103.6,40.5h17.6c0.9,0,2.1,0.7,2.6,1.5v0l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5
|
||||
h-17.6c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3L101,42C101.5,41.2,102.7,40.5,103.6,40.5z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M68.6,56.8l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6c0.9,0,2.1,0.7,2.6,1.5
|
||||
l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5H71.2C70.3,58.3,69.1,57.6,68.6,56.8z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M67.7,97.7l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5H38.8c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3
|
||||
l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2C68.2,95.5,68.2,96.9,67.7,97.7z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M88.8,95.7H71.2c-0.9,0-2.1-0.7-2.6-1.5L59.8,79c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6
|
||||
c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2C90.9,95,89.7,95.7,88.8,95.7z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M132.6,97.7l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2
|
||||
c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6c0.9,0,2.1,0.7,2.6,1.5v0l8.8,15.2C133,95.5,133,96.9,132.6,97.7z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M153.6,95.7H136c-0.9,0-2.1-0.7-2.6-1.5L124.6,79c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5
|
||||
h17.6c0.9,0,2.1,0.7,2.6,1.5L165,76c0.5,0.8,0.5,2.2,0,3l-8.8,15.2C155.7,95,154.5,95.7,153.6,95.7z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M133.4,169l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6c0.9,0,2.1,0.7,2.6,1.5
|
||||
l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5H136C135.1,170.5,133.9,169.8,133.4,169z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M165,191.2l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5H136c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3
|
||||
l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2C165.4,189.1,165.4,190.4,165,191.2z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M200.8,171.5h17.6c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5
|
||||
h-17.6c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3l8.8-15.2C198.7,172.2,199.9,171.5,200.8,171.5z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M188.6,154.3l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6c-0.9,0-2.1-0.7-2.6-1.5
|
||||
l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5H186C186.9,152.8,188.1,153.5,188.6,154.3z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M197.4,135.1l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2
|
||||
c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5H186c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2C197.8,132.9,197.8,134.3,197.4,135.1
|
||||
z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M229.8,116.4l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2
|
||||
c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2
|
||||
C230.2,114.2,230.2,115.6,229.8,116.4z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M253.4,79.5l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6c-0.9,0-2.1-0.7-2.6-1.5
|
||||
l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6C251.7,78,252.9,78.6,253.4,79.5z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M262.2,60.2l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2
|
||||
c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2C262.7,58.1,262.7,59.4,262.2,60.2z"
|
||||
/>
|
||||
<path
|
||||
className="explore-graphic--hex"
|
||||
d="M294.6,41.5l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2
|
||||
c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2C295.1,39.4,295.1,40.7,294.6,41.5z"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
id="DiagnosticB"
|
||||
className="explore-graphic--diagnostic diagnostic-b"
|
||||
d="M178.4,10.4c0-1-0.8-1.9-1.9-1.9s-1.9,0.8-1.9,1.9c0,0.9,0.6,1.6,1.4,1.8v73.6
|
||||
c0,0.3,0.2,0.5,0.5,0.5s0.5-0.2,0.5-0.5V12.2C177.8,12,178.4,11.3,178.4,10.4z"
|
||||
/>
|
||||
<path
|
||||
id="DiagnosticA"
|
||||
className="explore-graphic--diagnostic diagnostic-a"
|
||||
d="M48.1,206.3v-59.9c0-0.3-0.2-0.5-0.5-0.5s-0.5,0.2-0.5,0.5v59.9c-0.8,0.2-1.4,0.9-1.4,1.8
|
||||
c0,1,0.8,1.9,1.9,1.9s1.9-0.8,1.9-1.9C49.5,207.2,48.9,206.5,48.1,206.3z"
|
||||
/>
|
||||
<g className="explore-graphic--flows">
|
||||
<path
|
||||
id="FlowB"
|
||||
className="explore-graphic--flow flow-b"
|
||||
d="M47.6,134.9l30,16.5c1,0.5,2.2,0.5,3.2,0l30-16.9c1-0.6,2.2-0.6,3.2,0l29.1,16.8
|
||||
c1,0.6,2.3,0.6,3.3,0l29.1-16.8c1-0.6,1.6-1.7,1.6-2.8V95.2"
|
||||
/>
|
||||
<path
|
||||
id="FlowA"
|
||||
className="explore-graphic--flow flow-a"
|
||||
d="M47.6,134.9l30.1-19c0.9-0.6,1.5-1.6,1.5-2.8V79.4c0-1.2,0.6-2.3,1.7-2.9l29.9-16.9
|
||||
c1-0.6,2.2-0.6,3.2,0l30.9,17.8l32.3,17.8"
|
||||
/>
|
||||
</g>
|
||||
<g id="Text">
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="52.6"
|
||||
y1="203.1"
|
||||
x2="75.2"
|
||||
y2="203.1"
|
||||
/>
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="52.6"
|
||||
y1="199.1"
|
||||
x2="79.2"
|
||||
y2="199.1"
|
||||
/>
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="52.6"
|
||||
y1="195.1"
|
||||
x2="83.5"
|
||||
y2="195.1"
|
||||
/>
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="52.6"
|
||||
y1="191.1"
|
||||
x2="69.4"
|
||||
y2="191.1"
|
||||
/>
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="171.5"
|
||||
y1="15.4"
|
||||
x2="148.9"
|
||||
y2="15.4"
|
||||
/>
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="171.5"
|
||||
y1="19.4"
|
||||
x2="155.3"
|
||||
y2="19.4"
|
||||
/>
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="171.5"
|
||||
y1="23.4"
|
||||
x2="146.3"
|
||||
y2="23.4"
|
||||
/>
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="171.5"
|
||||
y1="27.4"
|
||||
x2="159.3"
|
||||
y2="27.4"
|
||||
/>
|
||||
<line
|
||||
className="explore-graphic--text"
|
||||
x1="155.3"
|
||||
y1="27.4"
|
||||
x2="149.2"
|
||||
y2="27.4"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
id="HighlightA"
|
||||
className="explore-graphic--hex hex-a"
|
||||
d="M58.9,116.9l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5H38.8
|
||||
c-0.9,0-2.1-0.7-2.6-1.5l-8.8-15.2c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5h17.6C57.3,115.4,58.5,116.1,58.9,116.9z
|
||||
"
|
||||
/>
|
||||
<path
|
||||
id="HighlightB"
|
||||
className="explore-graphic--hex hex-b"
|
||||
d="M165.8,112.9L157,97.7c-0.5-0.8-0.5-2.2,0-3l8.8-15.2c0.5-0.8,1.6-1.5,2.6-1.5H186
|
||||
c0.9,0,2.1,0.7,2.6,1.5l8.8,15.2c0.5,0.8,0.5,2.2,0,3l-8.8,15.2c-0.5,0.8-1.6,1.5-2.6,1.5h-17.6
|
||||
C167.5,114.4,166.3,113.7,165.8,112.9z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -88,6 +88,7 @@ export class LineProtocol extends PureComponent<Props> {
|
|||
tabs={this.LineProtocolTabs}
|
||||
bucket={bucket}
|
||||
org={org}
|
||||
handleSubmit={this.handleSubmit}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ interface OwnProps {
|
|||
tabs: LineProtocolTab[]
|
||||
bucket: string
|
||||
org: string
|
||||
handleSubmit?: () => void
|
||||
}
|
||||
|
||||
type Props = OwnProps & DispatchProps & StateProps
|
||||
|
@ -69,6 +70,7 @@ export class LineProtocolTabs extends PureComponent<Props, State> {
|
|||
tabs,
|
||||
setLineProtocolBody,
|
||||
lineProtocolBody,
|
||||
handleSubmit,
|
||||
} = this.props
|
||||
|
||||
const {urlInput} = this.state
|
||||
|
@ -83,7 +85,13 @@ export class LineProtocolTabs extends PureComponent<Props, State> {
|
|||
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
<Grid.Column widthXS={Columns.Twelve}>
|
||||
<Grid.Column
|
||||
widthXS={Columns.Twelve}
|
||||
widthMD={Columns.Ten}
|
||||
offsetMD={Columns.One}
|
||||
widthLG={Columns.Eight}
|
||||
offsetLG={Columns.Two}
|
||||
>
|
||||
<div className="onboarding--admin-user-form">
|
||||
<div className={'wizard-step--lp-body'}>
|
||||
<TabBody
|
||||
|
@ -93,6 +101,7 @@ export class LineProtocolTabs extends PureComponent<Props, State> {
|
|||
urlInput={urlInput}
|
||||
lineProtocolBody={lineProtocolBody}
|
||||
setLineProtocolBody={setLineProtocolBody}
|
||||
handleSubmit={handleSubmit}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -21,23 +21,19 @@ interface Props {
|
|||
setLineProtocolBody: typeof setLineProtocolBody
|
||||
onURLChange: (url: string) => void
|
||||
urlInput: string
|
||||
handleSubmit?: () => void
|
||||
}
|
||||
|
||||
export default class extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
setLineProtocolBody,
|
||||
lineProtocolBody,
|
||||
activeLPTab,
|
||||
urlInput,
|
||||
} = this.props
|
||||
const {lineProtocolBody, activeLPTab, urlInput} = this.props
|
||||
|
||||
switch (activeLPTab) {
|
||||
case LineProtocolTab.UploadFile:
|
||||
return (
|
||||
<DragAndDrop
|
||||
submitText="Upload File"
|
||||
handleSubmit={setLineProtocolBody}
|
||||
handleSubmit={this.handleSetLineProtocol}
|
||||
submitOnDrop={true}
|
||||
submitOnUpload={true}
|
||||
/>
|
||||
|
@ -47,7 +43,7 @@ export default class extends PureComponent<Props> {
|
|||
<TextArea
|
||||
value={lineProtocolBody}
|
||||
placeholder="Write text here"
|
||||
onChange={setLineProtocolBody}
|
||||
onChange={this.handleSetLineProtocol}
|
||||
/>
|
||||
)
|
||||
case LineProtocolTab.EnterURL:
|
||||
|
@ -81,4 +77,12 @@ export default class extends PureComponent<Props> {
|
|||
const {value} = e.target
|
||||
this.props.onURLChange(value)
|
||||
}
|
||||
|
||||
private handleSetLineProtocol = async (lpBody: string) => {
|
||||
const {setLineProtocolBody, handleSubmit} = this.props
|
||||
await setLineProtocolBody(lpBody)
|
||||
if (handleSubmit) {
|
||||
handleSubmit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ exports[`LineProtocol rendering renders! 1`] = `
|
|||
</h5>
|
||||
<Connect(LineProtocolTabs)
|
||||
bucket="a"
|
||||
handleSubmit={[Function]}
|
||||
org="a"
|
||||
tabs={
|
||||
Array [
|
||||
|
|
|
@ -15,6 +15,10 @@ exports[`LineProtocolTabs rendering renders! 1`] = `
|
|||
<Grid>
|
||||
<GridRow>
|
||||
<GridColumn
|
||||
offsetLG={2}
|
||||
offsetMD={1}
|
||||
widthLG={8}
|
||||
widthMD={10}
|
||||
widthXS={12}
|
||||
>
|
||||
<div
|
||||
|
|
|
@ -2,10 +2,13 @@ import React, {SFC} from 'react'
|
|||
|
||||
interface Props {
|
||||
title: string
|
||||
altText?: string
|
||||
}
|
||||
|
||||
const PageTitle: SFC<Props> = ({title}) => (
|
||||
<h1 className="page--title">{title}</h1>
|
||||
const PageTitle: SFC<Props> = ({title, altText}) => (
|
||||
<h1 className="page--title" title={altText}>
|
||||
{title}
|
||||
</h1>
|
||||
)
|
||||
|
||||
export default PageTitle
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
margin-top: 18px;
|
||||
> button.btn {
|
||||
> button {
|
||||
margin: 0 4px;
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@
|
|||
right: 20px;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
> button.btn {
|
||||
> button {
|
||||
margin: 2px 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import classnames from 'classnames'
|
||||
import {Button, ComponentColor, ComponentSize, ButtonType} from 'src/clockface'
|
||||
|
||||
import './DragAndDrop.scss'
|
||||
|
||||
|
@ -133,29 +134,33 @@ class DragAndDrop extends PureComponent<Props, State> {
|
|||
if (submitOnDrop) {
|
||||
return (
|
||||
<span className="drag-and-drop--buttons">
|
||||
<button
|
||||
className="btn btn-sm btn-default"
|
||||
<Button
|
||||
color={ComponentColor.Default}
|
||||
text="Cancel"
|
||||
size={ComponentSize.Medium}
|
||||
type={ButtonType.Button}
|
||||
onClick={this.handleCancelFile}
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="drag-and-drop--buttons">
|
||||
<button className="btn btn-sm btn-success" onClick={this.handleSubmit}>
|
||||
{submitText}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-sm btn-default"
|
||||
<Button
|
||||
color={ComponentColor.Primary}
|
||||
text={submitText}
|
||||
size={ComponentSize.Medium}
|
||||
type={ButtonType.Submit}
|
||||
onClick={this.handleSubmit}
|
||||
/>
|
||||
<Button
|
||||
color={ComponentColor.Default}
|
||||
text="Cancel"
|
||||
size={ComponentSize.Medium}
|
||||
type={ButtonType.Submit}
|
||||
onClick={this.handleCancelFile}
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -32,6 +32,10 @@ export default class EmptyQueryView extends PureComponent<Props> {
|
|||
fallbackNote,
|
||||
} = this.props
|
||||
|
||||
if (loading === RemoteDataState.NotStarted) {
|
||||
return <EmptyGraphMessage message={emptyGraphCopy} />
|
||||
}
|
||||
|
||||
if (!queries.length) {
|
||||
return <EmptyGraphMessage message={emptyGraphCopy} />
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import {connect} from 'react-redux'
|
|||
import {get} from 'lodash'
|
||||
|
||||
// Components
|
||||
import TimeMachineControls from 'src/shared/components/TimeMachineControls'
|
||||
import {DraggableResizer, Stack} from 'src/clockface'
|
||||
import TimeMachineBottom from 'src/shared/components/TimeMachineBottom'
|
||||
import TimeMachineVis from 'src/shared/components/TimeMachineVis'
|
||||
|
@ -64,7 +63,6 @@ class TimeMachine extends Component<Props, State> {
|
|||
>
|
||||
<DraggableResizer.Panel>
|
||||
<div className="time-machine--top">
|
||||
<TimeMachineControls queriesState={queriesState} />
|
||||
<TimeMachineVis queriesState={queriesState} />
|
||||
</div>
|
||||
</DraggableResizer.Panel>
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import TimeRangeDropdown from 'src/shared/components/TimeRangeDropdown'
|
||||
import CSVExportButton from 'src/shared/components/CSVExportButton'
|
||||
import {
|
||||
SlideToggle,
|
||||
ComponentSize,
|
||||
ComponentSpacer,
|
||||
Alignment,
|
||||
} from 'src/clockface'
|
||||
import TimeMachineRefreshDropdown from 'src/shared/components/TimeMachineRefreshDropdown'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
setTimeRange,
|
||||
setIsViewingRawData,
|
||||
} from 'src/shared/actions/v2/timeMachines'
|
||||
|
||||
// Utils
|
||||
import {getActiveTimeMachine} from 'src/shared/selectors/timeMachines'
|
||||
|
||||
// Types
|
||||
import {TimeRange, AppState} from 'src/types/v2'
|
||||
import {QueriesState} from 'src/shared/components/TimeSeries'
|
||||
|
||||
interface StateProps {
|
||||
timeRange: TimeRange
|
||||
isViewingRawData: boolean
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onSetTimeRange: (timeRange: TimeRange) => void
|
||||
onSetIsViewingRawData: typeof setIsViewingRawData
|
||||
}
|
||||
|
||||
interface OwnProps {
|
||||
queriesState: QueriesState
|
||||
}
|
||||
|
||||
type Props = StateProps & DispatchProps & OwnProps
|
||||
|
||||
class TimeMachineControls extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
timeRange,
|
||||
onSetTimeRange,
|
||||
isViewingRawData,
|
||||
queriesState: {files},
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="time-machine--controls">
|
||||
<ComponentSpacer align={Alignment.Right}>
|
||||
<SlideToggle.Label text="View Raw Data" />
|
||||
<SlideToggle
|
||||
active={isViewingRawData}
|
||||
onChange={this.handleToggleIsViewingRawData}
|
||||
size={ComponentSize.ExtraSmall}
|
||||
/>
|
||||
<CSVExportButton files={files} />
|
||||
<TimeMachineRefreshDropdown />
|
||||
<TimeRangeDropdown
|
||||
timeRange={timeRange}
|
||||
onSetTimeRange={onSetTimeRange}
|
||||
/>
|
||||
</ComponentSpacer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private handleToggleIsViewingRawData = () => {
|
||||
const {isViewingRawData, onSetIsViewingRawData} = this.props
|
||||
|
||||
onSetIsViewingRawData(!isViewingRawData)
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {timeRange, isViewingRawData} = getActiveTimeMachine(state)
|
||||
|
||||
return {timeRange, isViewingRawData}
|
||||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
onSetTimeRange: setTimeRange,
|
||||
onSetIsViewingRawData: setIsViewingRawData,
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps, OwnProps>(
|
||||
mstp,
|
||||
mdtp
|
||||
)(TimeMachineControls)
|
|
@ -1,10 +1,13 @@
|
|||
// Libraries
|
||||
import React, {SFC} from 'react'
|
||||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import TimeMachineFluxEditor from 'src/shared/components/TimeMachineFluxEditor'
|
||||
import CSVExportButton from 'src/shared/components/CSVExportButton'
|
||||
import TimeMachineQueriesSwitcher from 'src/shared/components/TimeMachineQueriesSwitcher'
|
||||
import TimeMachineRefreshDropdown from 'src/shared/components/TimeMachineRefreshDropdown'
|
||||
import TimeRangeDropdown from 'src/shared/components/TimeRangeDropdown'
|
||||
import TimeMachineQueryTab from 'src/shared/components/TimeMachineQueryTab'
|
||||
import TimeMachineQueryBuilder from 'src/shared/components/TimeMachineQueryBuilder'
|
||||
import TimeMachineInfluxQLEditor from 'src/shared/components/TimeMachineInfluxQLEditor'
|
||||
|
@ -12,14 +15,21 @@ import TimeMachineQueriesTimer from 'src/shared/components/TimeMachineQueriesTim
|
|||
import SubmitQueryButton from 'src/shared/components/SubmitQueryButton'
|
||||
import {
|
||||
Button,
|
||||
ComponentSpacer,
|
||||
Alignment,
|
||||
ComponentColor,
|
||||
ComponentSize,
|
||||
ButtonShape,
|
||||
IconFont,
|
||||
SlideToggle,
|
||||
} from 'src/clockface'
|
||||
|
||||
// Actions
|
||||
import {addQuery} from 'src/shared/actions/v2/timeMachines'
|
||||
import {
|
||||
setTimeRange,
|
||||
setIsViewingRawData,
|
||||
} from 'src/shared/actions/v2/timeMachines'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
|
@ -36,6 +46,7 @@ import {
|
|||
DashboardQuery,
|
||||
InfluxLanguage,
|
||||
QueryEditMode,
|
||||
TimeRange,
|
||||
} from 'src/types/v2'
|
||||
import {DashboardDraftQuery} from 'src/types/v2/dashboards'
|
||||
import {QueriesState} from 'src/shared/components/TimeSeries'
|
||||
|
@ -43,10 +54,14 @@ import {QueriesState} from 'src/shared/components/TimeSeries'
|
|||
interface StateProps {
|
||||
activeQuery: DashboardQuery
|
||||
draftQueries: DashboardDraftQuery[]
|
||||
timeRange: TimeRange
|
||||
isViewingRawData: boolean
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onAddQuery: typeof addQuery
|
||||
onSetTimeRange: typeof setTimeRange
|
||||
onSetIsViewingRawData: typeof setIsViewingRawData
|
||||
}
|
||||
|
||||
interface OwnProps {
|
||||
|
@ -55,62 +70,98 @@ interface OwnProps {
|
|||
|
||||
type Props = StateProps & DispatchProps & OwnProps
|
||||
|
||||
const TimeMachineQueries: SFC<Props> = props => {
|
||||
const {activeQuery, queriesState, draftQueries, onAddQuery} = props
|
||||
class TimeMachineQueries extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
queriesState,
|
||||
draftQueries,
|
||||
onAddQuery,
|
||||
timeRange,
|
||||
onSetTimeRange,
|
||||
isViewingRawData,
|
||||
queriesState: {files},
|
||||
} = this.props
|
||||
|
||||
let queryEditor
|
||||
|
||||
if (activeQuery.editMode === QueryEditMode.Builder) {
|
||||
queryEditor = <TimeMachineQueryBuilder />
|
||||
} else if (activeQuery.type === InfluxLanguage.Flux) {
|
||||
queryEditor = <TimeMachineFluxEditor />
|
||||
} else if (activeQuery.type === InfluxLanguage.InfluxQL) {
|
||||
queryEditor = <TimeMachineInfluxQLEditor />
|
||||
return (
|
||||
<div className="time-machine-queries">
|
||||
<div className="time-machine-queries--controls">
|
||||
<div className="time-machine-queries--tabs">
|
||||
{draftQueries.map((query, queryIndex) => (
|
||||
<TimeMachineQueryTab
|
||||
key={queryIndex}
|
||||
queryIndex={queryIndex}
|
||||
query={query}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
customClass="time-machine-queries--new"
|
||||
shape={ButtonShape.Square}
|
||||
icon={IconFont.PlusSkinny}
|
||||
size={ComponentSize.ExtraSmall}
|
||||
color={ComponentColor.Default}
|
||||
onClick={onAddQuery}
|
||||
/>
|
||||
</div>
|
||||
<div className="time-machine-queries--buttons">
|
||||
<TimeMachineQueriesTimer
|
||||
status={queriesState.loading}
|
||||
duration={queriesState.duration}
|
||||
/>
|
||||
<ComponentSpacer align={Alignment.Right}>
|
||||
<SlideToggle.Label text="View Raw Data" />
|
||||
<SlideToggle
|
||||
active={isViewingRawData}
|
||||
onChange={this.handleToggleIsViewingRawData}
|
||||
size={ComponentSize.ExtraSmall}
|
||||
/>
|
||||
<TimeMachineRefreshDropdown />
|
||||
<TimeRangeDropdown
|
||||
timeRange={timeRange}
|
||||
onSetTimeRange={onSetTimeRange}
|
||||
/>
|
||||
<TimeMachineQueriesSwitcher />
|
||||
<CSVExportButton files={files} />
|
||||
<SubmitQueryButton queryStatus={queriesState.loading} />
|
||||
</ComponentSpacer>
|
||||
</div>
|
||||
</div>
|
||||
<div className="time-machine-queries--body">{this.queryEditor}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="time-machine-queries">
|
||||
<div className="time-machine-queries--controls">
|
||||
<div className="time-machine-queries--tabs">
|
||||
{draftQueries.map((query, queryIndex) => (
|
||||
<TimeMachineQueryTab
|
||||
key={queryIndex}
|
||||
queryIndex={queryIndex}
|
||||
query={query}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
customClass="time-machine-queries--new"
|
||||
shape={ButtonShape.Square}
|
||||
icon={IconFont.PlusSkinny}
|
||||
size={ComponentSize.ExtraSmall}
|
||||
color={ComponentColor.Default}
|
||||
onClick={onAddQuery}
|
||||
/>
|
||||
</div>
|
||||
<div className="time-machine-queries--buttons">
|
||||
<TimeMachineQueriesTimer
|
||||
status={queriesState.loading}
|
||||
duration={queriesState.duration}
|
||||
/>
|
||||
<TimeMachineQueriesSwitcher />
|
||||
<SubmitQueryButton queryStatus={queriesState.loading} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="time-machine-queries--body">{queryEditor}</div>
|
||||
</div>
|
||||
)
|
||||
private get queryEditor(): JSX.Element {
|
||||
const {activeQuery} = this.props
|
||||
|
||||
if (activeQuery.editMode === QueryEditMode.Builder) {
|
||||
return <TimeMachineQueryBuilder />
|
||||
} else if (activeQuery.type === InfluxLanguage.Flux) {
|
||||
return <TimeMachineFluxEditor />
|
||||
} else if (activeQuery.type === InfluxLanguage.InfluxQL) {
|
||||
return <TimeMachineInfluxQLEditor />
|
||||
}
|
||||
}
|
||||
|
||||
private handleToggleIsViewingRawData = () => {
|
||||
const {isViewingRawData, onSetIsViewingRawData} = this.props
|
||||
|
||||
onSetIsViewingRawData(!isViewingRawData)
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const {draftQueries} = getActiveTimeMachine(state)
|
||||
const {draftQueries, timeRange, isViewingRawData} = getActiveTimeMachine(
|
||||
state
|
||||
)
|
||||
const activeQuery = getActiveQuery(state)
|
||||
|
||||
return {activeQuery, draftQueries}
|
||||
return {timeRange, activeQuery, draftQueries, isViewingRawData}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onAddQuery: addQuery,
|
||||
onSetTimeRange: setTimeRange,
|
||||
onSetIsViewingRawData: setIsViewingRawData,
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps, OwnProps>(
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
}
|
||||
|
||||
.task-form--options {
|
||||
flex: 1 0 0;
|
||||
flex: 1 0 140px;
|
||||
padding: $ix-marg-d;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
// Libraries
|
||||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
|
||||
// Components
|
||||
import TaskForm from 'src/tasks/components/TaskForm'
|
||||
import {Form} from 'src/clockface'
|
||||
|
||||
// Constants
|
||||
import defaultTaskOptions from 'src/tasks/reducers/v2'
|
||||
|
||||
const setup = (override?) => {
|
||||
const props = {
|
||||
orgs: [],
|
||||
taskOptions: defaultTaskOptions,
|
||||
onChangeScheduleType: jest.fn(),
|
||||
onChangeInput: jest.fn(),
|
||||
onChangeTaskOrgID: jest.fn(),
|
||||
...override,
|
||||
}
|
||||
|
||||
const wrapper = shallow(<TaskForm {...props} />)
|
||||
|
||||
return {wrapper}
|
||||
}
|
||||
|
||||
describe('TaskForm', () => {
|
||||
describe('rendering', () => {
|
||||
it('renders', () => {
|
||||
const {wrapper} = setup()
|
||||
const form = wrapper.find(Form)
|
||||
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
expect(form.exists()).toBe(true)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
|
@ -11,9 +11,11 @@ import {
|
|||
Input,
|
||||
Radio,
|
||||
ButtonShape,
|
||||
Button,
|
||||
ComponentColor,
|
||||
ButtonType,
|
||||
} from 'src/clockface'
|
||||
import TaskOptionsOrgDropdown from 'src/tasks/components/TasksOptionsOrgDropdown'
|
||||
import FluxEditor from 'src/shared/components/FluxEditor'
|
||||
import TaskScheduleFormField from 'src/tasks/components/TaskScheduleFormField'
|
||||
|
||||
// Types
|
||||
|
@ -25,132 +27,134 @@ import {Organization} from 'src/api'
|
|||
import './TaskForm.scss'
|
||||
|
||||
interface Props {
|
||||
script: string
|
||||
orgs: Organization[]
|
||||
taskOptions: TaskOptions
|
||||
onChangeScheduleType: (schedule: TaskSchedule) => void
|
||||
onChangeScript: (script: string) => void
|
||||
onChangeInput: (e: ChangeEvent<HTMLInputElement>) => void
|
||||
onChangeTaskOrgID: (orgID: string) => void
|
||||
isInOverlay?: boolean
|
||||
onSubmit?: () => void
|
||||
canSubmit?: boolean
|
||||
dismiss?: () => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
retryAttempts: string
|
||||
schedule: TaskSchedule
|
||||
}
|
||||
|
||||
export default class TaskForm extends PureComponent<Props, State> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
isInOverlay: false,
|
||||
onSubmit: () => {},
|
||||
canSubmit: true,
|
||||
dismiss: () => {},
|
||||
}
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
retryAttempts: '1',
|
||||
schedule: props.taskOptions.taskScheduleType,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
script,
|
||||
onChangeInput,
|
||||
onChangeScript,
|
||||
onChangeTaskOrgID,
|
||||
taskOptions: {name, taskScheduleType, interval, offset, cron, orgID},
|
||||
orgs,
|
||||
isInOverlay,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="task-form">
|
||||
<div className="task-form--options">
|
||||
<Form>
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
<Grid.Column widthXS={Columns.Twelve}>
|
||||
<Form.Element label="Name">
|
||||
<Input
|
||||
name="name"
|
||||
placeholder="Name your task"
|
||||
onChange={onChangeInput}
|
||||
value={name}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<Grid.Column widthXS={Columns.Twelve}>
|
||||
<Form.Element label="Owner">
|
||||
<TaskOptionsOrgDropdown
|
||||
orgs={orgs}
|
||||
selectedOrgID={orgID}
|
||||
onChangeTaskOrgID={onChangeTaskOrgID}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<Grid.Column widthXS={Columns.Twelve}>
|
||||
<Form.Element label="Schedule Task">
|
||||
<ComponentSpacer
|
||||
align={Alignment.Left}
|
||||
stackChildren={Stack.Rows}
|
||||
<Form>
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
<Grid.Column widthXS={Columns.Twelve}>
|
||||
<Form.Element label="Name">
|
||||
<Input
|
||||
name="name"
|
||||
placeholder="Name your task"
|
||||
onChange={onChangeInput}
|
||||
value={name}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<Grid.Column widthXS={Columns.Twelve}>
|
||||
<Form.Element label="Owner">
|
||||
<TaskOptionsOrgDropdown
|
||||
orgs={orgs}
|
||||
selectedOrgID={orgID}
|
||||
onChangeTaskOrgID={onChangeTaskOrgID}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Form.Element label="Schedule Task">
|
||||
<ComponentSpacer
|
||||
align={Alignment.Left}
|
||||
stackChildren={Stack.Rows}
|
||||
>
|
||||
<Radio shape={ButtonShape.StretchToFit}>
|
||||
<Radio.Button
|
||||
id="interval"
|
||||
active={taskScheduleType === TaskSchedule.interval}
|
||||
value={TaskSchedule.interval}
|
||||
titleText="Interval"
|
||||
onClick={this.handleChangeScheduleType}
|
||||
>
|
||||
<Radio shape={ButtonShape.StretchToFit}>
|
||||
<Radio.Button
|
||||
id="interval"
|
||||
active={taskScheduleType === TaskSchedule.interval}
|
||||
value={TaskSchedule.interval}
|
||||
titleText="Interval"
|
||||
onClick={this.handleChangeScheduleType}
|
||||
>
|
||||
Interval
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
id="cron"
|
||||
active={taskScheduleType === TaskSchedule.cron}
|
||||
value={TaskSchedule.cron}
|
||||
titleText="Cron"
|
||||
onClick={this.handleChangeScheduleType}
|
||||
>
|
||||
Cron
|
||||
</Radio.Button>
|
||||
</Radio>
|
||||
<TaskScheduleFormField
|
||||
onChangeInput={onChangeInput}
|
||||
schedule={taskScheduleType}
|
||||
interval={interval}
|
||||
offset={offset}
|
||||
cron={cron}
|
||||
/>
|
||||
</ComponentSpacer>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<Grid.Column widthXS={Columns.Twelve}>
|
||||
<Form.Element label="Retry attempts">
|
||||
<Input
|
||||
name="retry"
|
||||
placeholder=""
|
||||
onChange={this.handleChangeRetry}
|
||||
status={ComponentStatus.Disabled}
|
||||
value={this.state.retryAttempts}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Form>
|
||||
</div>
|
||||
<div className="task-form--editor">
|
||||
<FluxEditor
|
||||
script={script}
|
||||
onChangeScript={onChangeScript}
|
||||
visibility="visible"
|
||||
status={{text: '', type: ''}}
|
||||
suggestions={[]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
Interval
|
||||
</Radio.Button>
|
||||
<Radio.Button
|
||||
id="cron"
|
||||
active={taskScheduleType === TaskSchedule.cron}
|
||||
value={TaskSchedule.cron}
|
||||
titleText="Cron"
|
||||
onClick={this.handleChangeScheduleType}
|
||||
>
|
||||
Cron
|
||||
</Radio.Button>
|
||||
</Radio>
|
||||
</ComponentSpacer>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<TaskScheduleFormField
|
||||
onChangeInput={onChangeInput}
|
||||
schedule={taskScheduleType}
|
||||
interval={interval}
|
||||
offset={offset}
|
||||
cron={cron}
|
||||
/>
|
||||
{isInOverlay && this.buttons}
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
private handleChangeRetry = (e: ChangeEvent<HTMLInputElement>): void => {
|
||||
const retryAttempts = e.target.value
|
||||
this.setState({retryAttempts})
|
||||
private get buttons(): JSX.Element {
|
||||
const {onSubmit, canSubmit, dismiss} = this.props
|
||||
return (
|
||||
<Grid.Column widthXS={Columns.Twelve}>
|
||||
<Form.Footer>
|
||||
<Button
|
||||
text="Cancel"
|
||||
onClick={dismiss}
|
||||
titleText="Cancel save"
|
||||
type={ButtonType.Button}
|
||||
/>
|
||||
<Button
|
||||
text={'Save as Task'}
|
||||
color={ComponentColor.Success}
|
||||
type={ButtonType.Submit}
|
||||
onClick={onSubmit}
|
||||
status={
|
||||
canSubmit ? ComponentStatus.Default : ComponentStatus.Disabled
|
||||
}
|
||||
/>
|
||||
</Form.Footer>
|
||||
</Grid.Column>
|
||||
)
|
||||
}
|
||||
|
||||
private handleChangeScheduleType = (schedule: TaskSchedule): void => {
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
import {Page} from 'src/pageLayout'
|
||||
import {ComponentColor, Button} from 'src/clockface'
|
||||
import {ComponentColor, Button, ComponentStatus} from 'src/clockface'
|
||||
|
||||
import 'src/tasks/components/TasksPage.scss'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
canSubmit: boolean
|
||||
onCancel: () => void
|
||||
onSave: () => void
|
||||
}
|
||||
|
@ -27,6 +28,11 @@ export default class TaskHeader extends PureComponent<Props> {
|
|||
<Button
|
||||
color={ComponentColor.Success}
|
||||
text="Save"
|
||||
status={
|
||||
this.props.canSubmit
|
||||
? ComponentStatus.Default
|
||||
: ComponentStatus.Disabled
|
||||
}
|
||||
onClick={this.props.onSave}
|
||||
/>
|
||||
</Page.Header.Right>
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
import React, {PureComponent, ChangeEvent} from 'react'
|
||||
|
||||
// Components
|
||||
import {ComponentSpacer, Input, InputType} from 'src/clockface'
|
||||
import {Input, InputType, Grid, Form, Columns} from 'src/clockface'
|
||||
|
||||
// Types
|
||||
import {Alignment} from 'src/clockface'
|
||||
import {TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
|
||||
|
||||
interface Props {
|
||||
|
@ -22,31 +21,33 @@ export default class TaskScheduleFormFields extends PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<>
|
||||
<ComponentSpacer align={Alignment.Left} stretchToFitWidth={true}>
|
||||
<label className="task-form--form-label">
|
||||
{schedule === TaskSchedule.interval ? 'Interval' : 'Cron'}
|
||||
</label>
|
||||
<Input
|
||||
name={schedule}
|
||||
type={InputType.Text}
|
||||
placeholder={
|
||||
schedule === TaskSchedule.interval ? '1d3h30s' : '0 2 * * *'
|
||||
}
|
||||
value={schedule === TaskSchedule.interval ? interval : cron}
|
||||
onChange={this.props.onChangeInput}
|
||||
/>
|
||||
</ComponentSpacer>
|
||||
<Grid.Column widthXS={Columns.Six}>
|
||||
<Form.Element
|
||||
label={schedule === TaskSchedule.interval ? 'Interval' : 'Cron'}
|
||||
>
|
||||
<Input
|
||||
name={schedule}
|
||||
type={InputType.Text}
|
||||
placeholder={
|
||||
schedule === TaskSchedule.interval ? '1d3h30s' : '0 2 * * *'
|
||||
}
|
||||
value={schedule === TaskSchedule.interval ? interval : cron}
|
||||
onChange={this.props.onChangeInput}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
|
||||
<ComponentSpacer align={Alignment.Left} stretchToFitWidth={true}>
|
||||
<label className="task-form--form-label">Offset</label>
|
||||
<Input
|
||||
name="offset"
|
||||
type={InputType.Text}
|
||||
value={offset}
|
||||
placeholder="20m"
|
||||
onChange={onChangeInput}
|
||||
/>
|
||||
</ComponentSpacer>
|
||||
<Grid.Column widthXS={Columns.Six}>
|
||||
<Form.Element label="Offset">
|
||||
<Input
|
||||
name="offset"
|
||||
type={InputType.Text}
|
||||
value={offset}
|
||||
placeholder="20m"
|
||||
onChange={onChangeInput}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TaskForm rendering renders 1`] = `
|
||||
<Form>
|
||||
<Grid>
|
||||
<GridRow>
|
||||
<GridColumn
|
||||
widthXS={12}
|
||||
>
|
||||
<FormElement
|
||||
label="Name"
|
||||
>
|
||||
<Input
|
||||
autoFocus={false}
|
||||
autocomplete="off"
|
||||
disabledTitleText="This input is disabled"
|
||||
name="name"
|
||||
onChange={[MockFunction]}
|
||||
placeholder="Name your task"
|
||||
size="sm"
|
||||
spellCheck={false}
|
||||
status="default"
|
||||
titleText=""
|
||||
value=""
|
||||
/>
|
||||
</FormElement>
|
||||
</GridColumn>
|
||||
<GridColumn
|
||||
widthXS={12}
|
||||
>
|
||||
<FormElement
|
||||
label="Owner"
|
||||
>
|
||||
<TaskOptionsOrgDropdown
|
||||
onChangeTaskOrgID={[MockFunction]}
|
||||
orgs={Array []}
|
||||
/>
|
||||
</FormElement>
|
||||
</GridColumn>
|
||||
<GridColumn
|
||||
widthXS={12}
|
||||
>
|
||||
<FormElement
|
||||
label="Schedule Task"
|
||||
>
|
||||
<ComponentSpacer
|
||||
align="left"
|
||||
stackChildren="rows"
|
||||
>
|
||||
<Radio
|
||||
color="primary"
|
||||
shape="stretch"
|
||||
size="sm"
|
||||
>
|
||||
<RadioButton
|
||||
active={false}
|
||||
disabled={false}
|
||||
disabledTitleText="This option is disabled"
|
||||
id="interval"
|
||||
onClick={[Function]}
|
||||
titleText="Interval"
|
||||
value="interval"
|
||||
>
|
||||
Interval
|
||||
</RadioButton>
|
||||
<RadioButton
|
||||
active={false}
|
||||
disabled={false}
|
||||
disabledTitleText="This option is disabled"
|
||||
id="cron"
|
||||
onClick={[Function]}
|
||||
titleText="Cron"
|
||||
value="cron"
|
||||
>
|
||||
Cron
|
||||
</RadioButton>
|
||||
</Radio>
|
||||
</ComponentSpacer>
|
||||
</FormElement>
|
||||
</GridColumn>
|
||||
<TaskScheduleFormFields
|
||||
onChangeInput={[MockFunction]}
|
||||
/>
|
||||
</GridRow>
|
||||
</Grid>
|
||||
</Form>
|
||||
`;
|
|
@ -8,7 +8,7 @@ import {connect} from 'react-redux'
|
|||
import TaskForm from 'src/tasks/components/TaskForm'
|
||||
import TaskHeader from 'src/tasks/components/TaskHeader'
|
||||
import {Page} from 'src/pageLayout'
|
||||
import {Task as TaskAPI, User, Organization} from 'src/api'
|
||||
import FluxEditor from 'src/shared/components/FluxEditor'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
|
@ -22,6 +22,7 @@ import {
|
|||
} from 'src/tasks/actions/v2'
|
||||
|
||||
// Types
|
||||
import {Task as TaskAPI, User, Organization} from 'src/api'
|
||||
import {Links} from 'src/types/v2/links'
|
||||
import {State as TasksState} from 'src/tasks/reducers/v2'
|
||||
import {
|
||||
|
@ -88,24 +89,47 @@ class TaskPage extends PureComponent<
|
|||
<Page titleTag={`Edit ${taskOptions.name}`}>
|
||||
<TaskHeader
|
||||
title="Update Task"
|
||||
canSubmit={this.isFormValid}
|
||||
onCancel={this.handleCancel}
|
||||
onSave={this.handleSave}
|
||||
/>
|
||||
<Page.Contents fullWidth={true} scrollable={false}>
|
||||
<TaskForm
|
||||
orgs={orgs}
|
||||
script={currentScript}
|
||||
taskOptions={taskOptions}
|
||||
onChangeScript={this.handleChangeScript}
|
||||
onChangeScheduleType={this.handleChangeScheduleType}
|
||||
onChangeInput={this.handleChangeInput}
|
||||
onChangeTaskOrgID={this.handleChangeTaskOrgID}
|
||||
/>
|
||||
<div className="task-form">
|
||||
<div className="task-form--options">
|
||||
<TaskForm
|
||||
orgs={orgs}
|
||||
canSubmit={this.isFormValid}
|
||||
taskOptions={taskOptions}
|
||||
onChangeInput={this.handleChangeInput}
|
||||
onChangeScheduleType={this.handleChangeScheduleType}
|
||||
onChangeTaskOrgID={this.handleChangeTaskOrgID}
|
||||
/>
|
||||
</div>
|
||||
<div className="task-form--editor">
|
||||
<FluxEditor
|
||||
script={currentScript}
|
||||
onChangeScript={this.handleChangeScript}
|
||||
visibility="visible"
|
||||
status={{text: '', type: ''}}
|
||||
suggestions={[]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
private get isFormValid(): boolean {
|
||||
const {
|
||||
taskOptions: {name, cron, interval},
|
||||
currentScript,
|
||||
} = this.props
|
||||
|
||||
const hasSchedule = !!cron || !!interval
|
||||
return hasSchedule && !!name && !!currentScript
|
||||
}
|
||||
|
||||
private handleChangeScript = (script: string) => {
|
||||
this.props.setCurrentScript(script)
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ import React, {PureComponent, ChangeEvent} from 'react'
|
|||
import {InjectedRouter} from 'react-router'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// components
|
||||
import TaskForm from 'src/tasks/components/TaskForm'
|
||||
import TaskHeader from 'src/tasks/components/TaskHeader'
|
||||
import FluxEditor from 'src/shared/components/FluxEditor'
|
||||
import {Page} from 'src/pageLayout'
|
||||
|
||||
import {Links} from 'src/types/v2/links'
|
||||
// actions
|
||||
import {State as TasksState} from 'src/tasks/reducers/v2'
|
||||
import {
|
||||
setNewScript,
|
||||
|
@ -16,12 +18,17 @@ import {
|
|||
setTaskOption,
|
||||
clearTask,
|
||||
} from 'src/tasks/actions/v2'
|
||||
// types
|
||||
import {Links} from 'src/types/v2/links'
|
||||
import {Organization} from 'src/types/v2'
|
||||
import {
|
||||
TaskOptions,
|
||||
TaskOptionKeys,
|
||||
TaskSchedule,
|
||||
} from 'src/utils/taskOptionsToFluxScript'
|
||||
import {Organization} from 'src/types/v2'
|
||||
|
||||
// Styles
|
||||
import 'src/tasks/components/TaskForm.scss'
|
||||
|
||||
interface PassedInProps {
|
||||
router: InjectedRouter
|
||||
|
@ -67,24 +74,47 @@ class TaskPage extends PureComponent<
|
|||
<Page titleTag="Create Task">
|
||||
<TaskHeader
|
||||
title="Create Task"
|
||||
canSubmit={this.isFormValid}
|
||||
onCancel={this.handleCancel}
|
||||
onSave={this.handleSave}
|
||||
/>
|
||||
<Page.Contents fullWidth={true} scrollable={false}>
|
||||
<TaskForm
|
||||
orgs={orgs}
|
||||
script={newScript}
|
||||
taskOptions={taskOptions}
|
||||
onChangeInput={this.handleChangeInput}
|
||||
onChangeScheduleType={this.handleChangeScheduleType}
|
||||
onChangeScript={this.handleChangeScript}
|
||||
onChangeTaskOrgID={this.handleChangeTaskOrgID}
|
||||
/>
|
||||
<div className="task-form">
|
||||
<div className="task-form--options">
|
||||
<TaskForm
|
||||
orgs={orgs}
|
||||
canSubmit={this.isFormValid}
|
||||
taskOptions={taskOptions}
|
||||
onChangeInput={this.handleChangeInput}
|
||||
onChangeScheduleType={this.handleChangeScheduleType}
|
||||
onChangeTaskOrgID={this.handleChangeTaskOrgID}
|
||||
/>
|
||||
</div>
|
||||
<div className="task-form--editor">
|
||||
<FluxEditor
|
||||
script={newScript}
|
||||
onChangeScript={this.handleChangeScript}
|
||||
visibility="visible"
|
||||
status={{text: '', type: ''}}
|
||||
suggestions={[]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
private get isFormValid(): boolean {
|
||||
const {
|
||||
taskOptions: {name, cron, interval},
|
||||
newScript,
|
||||
} = this.props
|
||||
|
||||
const hasSchedule = !!cron || !!interval
|
||||
return hasSchedule && !!name && !!newScript
|
||||
}
|
||||
|
||||
private handleChangeScript = (script: string) => {
|
||||
this.props.setNewScript(script)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ export interface State {
|
|||
taskOptions: TaskOptions
|
||||
}
|
||||
|
||||
const defaultTaskOptions: TaskOptions = {
|
||||
export const defaultTaskOptions: TaskOptions = {
|
||||
name: '',
|
||||
interval: '',
|
||||
offset: '',
|
||||
|
|
Loading…
Reference in New Issue