feat/gitops/image-registry: Added revamped UI screens for Gitops and image registry (#4135)

* Added image registry screens

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* Update getImageRegistry API to fetch on projectID

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* Added gitops screens

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* Added API integration for image-registry

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* Added api integration for image registry

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* Added api integration for gitops

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* updated gitops to schema to follow convention

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* Added strings for image registry n gitops

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* resolved review comments

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* Resolved review comments

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* resolved comments

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

* fixed imports

Signed-off-by: Saranya-jena <saranya.jena@harness.io>

---------

Signed-off-by: Saranya-jena <saranya.jena@harness.io>
This commit is contained in:
Saranya Jena 2023-09-05 12:12:23 +05:30 committed by GitHub
parent 271d7fde97
commit 2d18956436
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1449 additions and 92 deletions

View File

@ -17,10 +17,6 @@ type SSHKey {
Details of setting a Git repository
"""
input GitConfig {
"""
ID of the project where GitOps is configured
"""
projectID: ID!
"""
Git branch where the chaos charts will be pushed and synced
"""
@ -112,15 +108,15 @@ extend type Mutation {
"""
Enables gitops settings in the project
"""
enableGitOps(configurations: GitConfig!): Boolean! @authorized
enableGitOps(projectID: ID!,configurations: GitConfig!): Boolean! @authorized
"""
Disables gitops settings in the project
"""
disableGitOps(projectID: String!): Boolean! @authorized
disableGitOps(projectID: ID!): Boolean! @authorized
"""
Updates gitops settings in the project
"""
updateGitOps(configurations: GitConfig!): Boolean! @authorized
updateGitOps(projectID: ID!,configurations: GitConfig!): Boolean! @authorized
}

View File

@ -113,7 +113,6 @@ extend type Query {
listImageRegistry(projectID: String!): [ImageRegistryResponse!] @authorized
getImageRegistry(
imageRegistryID: String!
projectID: String!
): ImageRegistryResponse! @authorized
}

View File

@ -1400,7 +1400,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@ -486,7 +486,7 @@ type ComplexityRoot struct {
DeleteInfra func(childComplexity int, projectID string, infraID string) int
DeleteProbe func(childComplexity int, probeName string, projectID string) int
DisableGitOps func(childComplexity int, projectID string) int
EnableGitOps func(childComplexity int, configurations model.GitConfig) int
EnableGitOps func(childComplexity int, projectID string, configurations model.GitConfig) int
GenerateSSHKey func(childComplexity int) int
GetManifestWithInfraID func(childComplexity int, projectID string, infraID string, accessKey string) int
GitopsNotifier func(childComplexity int, clusterInfo model.InfraIdentity, experimentID string) int
@ -500,7 +500,7 @@ type ComplexityRoot struct {
UpdateChaosExperiment func(childComplexity int, request *model.ChaosExperimentRequest, projectID string) int
UpdateChaosHub func(childComplexity int, projectID string, request model.UpdateChaosHubRequest) int
UpdateEnvironment func(childComplexity int, projectID string, request *model.UpdateEnvironmentRequest) int
UpdateGitOps func(childComplexity int, configurations model.GitConfig) int
UpdateGitOps func(childComplexity int, projectID string, configurations model.GitConfig) int
UpdateImageRegistry func(childComplexity int, imageRegistryID string, projectID string, imageRegistryInfo model.ImageRegistryInput) int
UpdateProbe func(childComplexity int, request model.ProbeRequest, projectID string) int
}
@ -589,7 +589,7 @@ type ComplexityRoot struct {
GetExperimentRunStats func(childComplexity int, projectID string) int
GetExperimentStats func(childComplexity int, projectID string) int
GetGitOpsDetails func(childComplexity int, projectID string) int
GetImageRegistry func(childComplexity int, imageRegistryID string, projectID string) int
GetImageRegistry func(childComplexity int, projectID string) int
GetInfra func(childComplexity int, projectID string, infraID string) int
GetInfraDetails func(childComplexity int, infraID string, projectID string) int
GetInfraManifest func(childComplexity int, infraID string, upgrade bool, projectID string) int
@ -725,9 +725,9 @@ type MutationResolver interface {
UpdateEnvironment(ctx context.Context, projectID string, request *model.UpdateEnvironmentRequest) (string, error)
DeleteEnvironment(ctx context.Context, projectID string, environmentID string) (string, error)
GitopsNotifier(ctx context.Context, clusterInfo model.InfraIdentity, experimentID string) (string, error)
EnableGitOps(ctx context.Context, configurations model.GitConfig) (bool, error)
EnableGitOps(ctx context.Context, projectID string, configurations model.GitConfig) (bool, error)
DisableGitOps(ctx context.Context, projectID string) (bool, error)
UpdateGitOps(ctx context.Context, configurations model.GitConfig) (bool, error)
UpdateGitOps(ctx context.Context, projectID string, configurations model.GitConfig) (bool, error)
CreateImageRegistry(ctx context.Context, projectID string, imageRegistryInfo model.ImageRegistryInput) (*model.ImageRegistryResponse, error)
UpdateImageRegistry(ctx context.Context, imageRegistryID string, projectID string, imageRegistryInfo model.ImageRegistryInput) (*model.ImageRegistryResponse, error)
DeleteImageRegistry(ctx context.Context, imageRegistryID string, projectID string) (string, error)
@ -760,7 +760,7 @@ type QueryResolver interface {
ListEnvironments(ctx context.Context, projectID string, request *model.ListEnvironmentRequest) (*model.ListEnvironmentResponse, error)
GetGitOpsDetails(ctx context.Context, projectID string) (*model.GitConfigResponse, error)
ListImageRegistry(ctx context.Context, projectID string) ([]*model.ImageRegistryResponse, error)
GetImageRegistry(ctx context.Context, imageRegistryID string, projectID string) (*model.ImageRegistryResponse, error)
GetImageRegistry(ctx context.Context, projectID string) (*model.ImageRegistryResponse, error)
ListProbes(ctx context.Context, projectID string, probeNames []string, filter *model.ProbeFilterInput) ([]*model.Probe, error)
GetProbe(ctx context.Context, projectID string, probeName string) (*model.Probe, error)
GetProbeYaml(ctx context.Context, projectID string, request model.GetProbeYAMLRequest) (string, error)
@ -2996,7 +2996,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Mutation.EnableGitOps(childComplexity, args["configurations"].(model.GitConfig)), true
return e.complexity.Mutation.EnableGitOps(childComplexity, args["projectID"].(string), args["configurations"].(model.GitConfig)), true
case "Mutation.generateSSHKey":
if e.complexity.Mutation.GenerateSSHKey == nil {
@ -3159,7 +3159,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Mutation.UpdateGitOps(childComplexity, args["configurations"].(model.GitConfig)), true
return e.complexity.Mutation.UpdateGitOps(childComplexity, args["projectID"].(string), args["configurations"].(model.GitConfig)), true
case "Mutation.updateImageRegistry":
if e.complexity.Mutation.UpdateImageRegistry == nil {
@ -3632,7 +3632,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.GetImageRegistry(childComplexity, args["imageRegistryID"].(string), args["projectID"].(string)), true
return e.complexity.Query.GetImageRegistry(childComplexity, args["projectID"].(string)), true
case "Query.getInfra":
if e.complexity.Query.GetInfra == nil {
@ -6592,10 +6592,6 @@ type SSHKey {
Details of setting a Git repository
"""
input GitConfig {
"""
ID of the project where GitOps is configured
"""
projectID: ID!
"""
Git branch where the chaos charts will be pushed and synced
"""
@ -6687,17 +6683,17 @@ extend type Mutation {
"""
Enables gitops settings in the project
"""
enableGitOps(configurations: GitConfig!): Boolean! @authorized
enableGitOps(projectID: ID!,configurations: GitConfig!): Boolean! @authorized
"""
Disables gitops settings in the project
"""
disableGitOps(projectID: String!): Boolean! @authorized
disableGitOps(projectID: ID!): Boolean! @authorized
"""
Updates gitops settings in the project
"""
updateGitOps(configurations: GitConfig!): Boolean! @authorized
updateGitOps(projectID: ID!,configurations: GitConfig!): Boolean! @authorized
}`, BuiltIn: false},
&ast.Source{Name: "../definitions/shared/image_registry.graphqls", Input: `"""
Defines details for image registry
@ -6814,7 +6810,6 @@ extend type Query {
listImageRegistry(projectID: String!): [ImageRegistryResponse!] @authorized
getImageRegistry(
imageRegistryID: String!
projectID: String!
): ImageRegistryResponse! @authorized
}
@ -8174,7 +8169,7 @@ func (ec *executionContext) field_Mutation_disableGitOps_args(ctx context.Contex
args := map[string]interface{}{}
var arg0 string
if tmp, ok := rawArgs["projectID"]; ok {
arg0, err = ec.unmarshalNString2string(ctx, tmp)
arg0, err = ec.unmarshalNID2string(ctx, tmp)
if err != nil {
return nil, err
}
@ -8186,14 +8181,22 @@ func (ec *executionContext) field_Mutation_disableGitOps_args(ctx context.Contex
func (ec *executionContext) field_Mutation_enableGitOps_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 model.GitConfig
if tmp, ok := rawArgs["configurations"]; ok {
arg0, err = ec.unmarshalNGitConfig2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐGitConfig(ctx, tmp)
var arg0 string
if tmp, ok := rawArgs["projectID"]; ok {
arg0, err = ec.unmarshalNID2string(ctx, tmp)
if err != nil {
return nil, err
}
}
args["configurations"] = arg0
args["projectID"] = arg0
var arg1 model.GitConfig
if tmp, ok := rawArgs["configurations"]; ok {
arg1, err = ec.unmarshalNGitConfig2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐGitConfig(ctx, tmp)
if err != nil {
return nil, err
}
}
args["configurations"] = arg1
return args, nil
}
@ -8456,14 +8459,22 @@ func (ec *executionContext) field_Mutation_updateEnvironment_args(ctx context.Co
func (ec *executionContext) field_Mutation_updateGitOps_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 model.GitConfig
if tmp, ok := rawArgs["configurations"]; ok {
arg0, err = ec.unmarshalNGitConfig2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐGitConfig(ctx, tmp)
var arg0 string
if tmp, ok := rawArgs["projectID"]; ok {
arg0, err = ec.unmarshalNID2string(ctx, tmp)
if err != nil {
return nil, err
}
}
args["configurations"] = arg0
args["projectID"] = arg0
var arg1 model.GitConfig
if tmp, ok := rawArgs["configurations"]; ok {
arg1, err = ec.unmarshalNGitConfig2githubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐGitConfig(ctx, tmp)
if err != nil {
return nil, err
}
}
args["configurations"] = arg1
return args, nil
}
@ -8703,21 +8714,13 @@ func (ec *executionContext) field_Query_getImageRegistry_args(ctx context.Contex
var err error
args := map[string]interface{}{}
var arg0 string
if tmp, ok := rawArgs["imageRegistryID"]; ok {
if tmp, ok := rawArgs["projectID"]; ok {
arg0, err = ec.unmarshalNString2string(ctx, tmp)
if err != nil {
return nil, err
}
}
args["imageRegistryID"] = arg0
var arg1 string
if tmp, ok := rawArgs["projectID"]; ok {
arg1, err = ec.unmarshalNString2string(ctx, tmp)
if err != nil {
return nil, err
}
}
args["projectID"] = arg1
args["projectID"] = arg0
return args, nil
}
@ -19919,7 +19922,7 @@ func (ec *executionContext) _Mutation_enableGitOps(ctx context.Context, field gr
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
directive0 := func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().EnableGitOps(rctx, args["configurations"].(model.GitConfig))
return ec.resolvers.Mutation().EnableGitOps(rctx, args["projectID"].(string), args["configurations"].(model.GitConfig))
}
directive1 := func(ctx context.Context) (interface{}, error) {
if ec.directives.Authorized == nil {
@ -20041,7 +20044,7 @@ func (ec *executionContext) _Mutation_updateGitOps(ctx context.Context, field gr
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
directive0 := func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().UpdateGitOps(rctx, args["configurations"].(model.GitConfig))
return ec.resolvers.Mutation().UpdateGitOps(rctx, args["projectID"].(string), args["configurations"].(model.GitConfig))
}
directive1 := func(ctx context.Context) (interface{}, error) {
if ec.directives.Authorized == nil {
@ -23308,7 +23311,7 @@ func (ec *executionContext) _Query_getImageRegistry(ctx context.Context, field g
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
directive0 := func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().GetImageRegistry(rctx, args["imageRegistryID"].(string), args["projectID"].(string))
return ec.resolvers.Query().GetImageRegistry(rctx, args["projectID"].(string))
}
directive1 := func(ctx context.Context) (interface{}, error) {
if ec.directives.Authorized == nil {
@ -27391,12 +27394,6 @@ func (ec *executionContext) unmarshalInputGitConfig(ctx context.Context, obj int
for k, v := range asMap {
switch k {
case "projectID":
var err error
it.ProjectID, err = ec.unmarshalNID2string(ctx, v)
if err != nil {
return it, err
}
case "branch":
var err error
it.Branch, err = ec.unmarshalNString2string(ctx, v)

View File

@ -20,14 +20,14 @@ func (r *mutationResolver) GitopsNotifier(ctx context.Context, clusterInfo model
return r.gitopsService.GitOpsNotificationHandler(ctx, *infra, experimentID)
}
func (r *mutationResolver) EnableGitOps(ctx context.Context, configurations model.GitConfig) (bool, error) {
err := authorization.ValidateRole(ctx, configurations.ProjectID,
func (r *mutationResolver) EnableGitOps(ctx context.Context, projectID string, configurations model.GitConfig) (bool, error) {
err := authorization.ValidateRole(ctx, projectID,
authorization.MutationRbacRules[authorization.EnableGitOps],
model.InvitationAccepted.String())
if err != nil {
return false, err
}
return r.gitopsService.EnableGitOpsHandler(ctx, configurations)
return r.gitopsService.EnableGitOpsHandler(ctx, projectID, configurations)
}
func (r *mutationResolver) DisableGitOps(ctx context.Context, projectID string) (bool, error) {
@ -40,14 +40,14 @@ func (r *mutationResolver) DisableGitOps(ctx context.Context, projectID string)
return r.gitopsService.DisableGitOpsHandler(ctx, projectID)
}
func (r *mutationResolver) UpdateGitOps(ctx context.Context, configurations model.GitConfig) (bool, error) {
err := authorization.ValidateRole(ctx, configurations.ProjectID,
func (r *mutationResolver) UpdateGitOps(ctx context.Context, projectID string, configurations model.GitConfig) (bool, error) {
err := authorization.ValidateRole(ctx, projectID,
authorization.MutationRbacRules[authorization.UpdateGitOps],
model.InvitationAccepted.String())
if err != nil {
return false, err
}
return r.gitopsService.UpdateGitOpsDetailsHandler(ctx, configurations)
return r.gitopsService.UpdateGitOpsDetailsHandler(ctx, projectID, configurations)
}
func (r *queryResolver) GetGitOpsDetails(ctx context.Context, projectID string) (*model.GitConfigResponse, error) {

View File

@ -74,7 +74,7 @@ func (r *queryResolver) ListImageRegistry(ctx context.Context, projectID string)
return imageRegistries, err
}
func (r *queryResolver) GetImageRegistry(ctx context.Context, imageRegistryID string, projectID string) (*model.ImageRegistryResponse, error) {
func (r *queryResolver) GetImageRegistry(ctx context.Context, projectID string) (*model.ImageRegistryResponse, error) {
err := authorization.ValidateRole(ctx, projectID,
authorization.MutationRbacRules[authorization.GetImageRegistry],
model.InvitationAccepted.String())
@ -82,7 +82,7 @@ func (r *queryResolver) GetImageRegistry(ctx context.Context, imageRegistryID st
return nil, err
}
imageRegistry, err := r.imageRegistryService.GetImageRegistry(ctx, imageRegistryID, projectID)
imageRegistry, err := r.imageRegistryService.GetImageRegistry(ctx, projectID)
if err != nil {
logrus.Error(err)
}

View File

@ -720,8 +720,6 @@ type GetProbesInExperimentRunResponse struct {
// Details of setting a Git repository
type GitConfig struct {
// ID of the project where GitOps is configured
ProjectID string `json:"projectID"`
// Git branch where the chaos charts will be pushed and synced
Branch string `json:"branch"`
// URL of the Git repository

View File

@ -1,6 +1,8 @@
package gitops
import "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model"
import (
"github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model"
)
// GitConfigDB ...
type GitConfigDB struct {
@ -16,9 +18,9 @@ type GitConfigDB struct {
}
// GetGitConfigDB ...
func GetGitConfigDB(config model.GitConfig) GitConfigDB {
func GetGitConfigDB(projectID string, config model.GitConfig) GitConfigDB {
return GitConfigDB{
ProjectID: config.ProjectID,
ProjectID: projectID,
RepositoryURL: config.RepoURL,
Branch: config.Branch,
LatestCommit: "",

View File

@ -61,8 +61,8 @@ var (
ChaosExperimentRunsCollection: "chaosExperimentRuns",
ChaosProbeCollection: "chaosProbes",
ChaosHubCollection: "chaosHubs",
ImageRegistryCollection: "image-registry",
ServerConfigCollection: "server-config",
ImageRegistryCollection: "imageRegistry",
ServerConfigCollection: "serverConfig",
GitOpsCollection: "gitops",
UserCollection: "user",
ProjectCollection: "project",
@ -224,9 +224,20 @@ func (m *MongoClient) initAllCollection() {
},
})
if err != nil {
logrus.WithError(err).Fatal("Error Creating Index for GitOps Collection : ", err)
logrus.WithError(err).Fatal("Error Creating Index for GitOps Collection")
}
m.ImageRegistryCollection = m.Database.Collection(Collections[ImageRegistryCollection])
_, err = m.ImageRegistryCollection.Indexes().CreateMany(backgroundContext, []mongo.IndexModel{
{
Keys: bson.M{
"project_id": 1,
},
Options: options.Index().SetUnique(true),
},
})
if err != nil {
logrus.WithError(err).Fatal("Error Creating Index for Image Registry Collection")
}
m.ServerConfigCollection = m.Database.Collection(Collections[ServerConfigCollection])
_, err = m.ServerConfigCollection.Indexes().CreateMany(backgroundContext, []mongo.IndexModel{
{
@ -237,7 +248,7 @@ func (m *MongoClient) initAllCollection() {
},
})
if err != nil {
logrus.WithError(err).Fatal("Error Creating Index for Server Config Collection : ", err)
logrus.WithError(err).Fatal("Error Creating Index for Server Config Collection")
}
m.EnvironmentCollection = m.Database.Collection(Collections[EnvironmentCollection])
_, err = m.EnvironmentCollection.Indexes().CreateMany(backgroundContext, []mongo.IndexModel{

View File

@ -43,9 +43,9 @@ var (
type Service interface {
GitOpsNotificationHandler(ctx context.Context, infra chaos_infrastructure.ChaosInfra, experimentID string) (string, error)
EnableGitOpsHandler(ctx context.Context, config model.GitConfig) (bool, error)
EnableGitOpsHandler(ctx context.Context, projectID string, config model.GitConfig) (bool, error)
DisableGitOpsHandler(ctx context.Context, projectID string) (bool, error)
UpdateGitOpsDetailsHandler(ctx context.Context, config model.GitConfig) (bool, error)
UpdateGitOpsDetailsHandler(ctx context.Context, projectID string, config model.GitConfig) (bool, error)
GetGitOpsDetails(ctx context.Context, projectID string) (*model.GitConfigResponse, error)
UpsertExperimentToGit(ctx context.Context, projectID string, experiment *model.ChaosExperimentRequest) error
DeleteExperimentFromGit(ctx context.Context, projectID string, experiment *model.ChaosExperimentRequest) error
@ -108,9 +108,9 @@ func (g *gitOpsService) GitOpsNotificationHandler(ctx context.Context, infra cha
}
// EnableGitOpsHandler enables gitops for a particular project
func (g *gitOpsService) EnableGitOpsHandler(ctx context.Context, config model.GitConfig) (bool, error) {
gitLock.Lock(config.ProjectID, nil)
defer gitLock.Unlock(config.ProjectID, nil)
func (g *gitOpsService) EnableGitOpsHandler(ctx context.Context, projectID string, config model.GitConfig) (bool, error) {
gitLock.Lock(projectID, nil)
defer gitLock.Unlock(projectID, nil)
gitLock.Lock(config.RepoURL, &config.Branch)
defer gitLock.Unlock(config.RepoURL, &config.Branch)
@ -119,13 +119,13 @@ func (g *gitOpsService) EnableGitOpsHandler(ctx context.Context, config model.Gi
client, conn := grpc.GetAuthGRPCSvcClient(conn)
defer conn.Close()
_, err := grpc.GetProjectById(client, config.ProjectID)
_, err := grpc.GetProjectById(client, projectID)
if err != nil {
return false, errors.New("Failed to setup GitOps : " + err.Error())
}
logrus.Info("Enabling Gitops")
gitDB := gitops.GetGitConfigDB(config)
gitDB := gitops.GetGitConfigDB(projectID, config)
commit, err := SetupGitOps(GitUserFromContext(ctx), GetGitOpsConfig(gitDB))
if err != nil {
@ -161,14 +161,14 @@ func (g *gitOpsService) DisableGitOpsHandler(ctx context.Context, projectID stri
}
// UpdateGitOpsDetailsHandler updates an exiting gitops config for a project
func (g *gitOpsService) UpdateGitOpsDetailsHandler(ctx context.Context, config model.GitConfig) (bool, error) {
gitLock.Lock(config.ProjectID, nil)
defer gitLock.Unlock(config.ProjectID, nil)
func (g *gitOpsService) UpdateGitOpsDetailsHandler(ctx context.Context, projectID string, config model.GitConfig) (bool, error) {
gitLock.Lock(projectID, nil)
defer gitLock.Unlock(projectID, nil)
gitLock.Lock(config.RepoURL, &config.Branch)
defer gitLock.Unlock(config.RepoURL, &config.Branch)
existingConfig, err := g.gitOpsOperator.GetGitConfig(ctx, config.ProjectID)
existingConfig, err := g.gitOpsOperator.GetGitConfig(ctx, projectID)
if err != nil {
return false, errors.New("Cannot get Git Config from DB : " + err.Error())
}
@ -177,7 +177,7 @@ func (g *gitOpsService) UpdateGitOpsDetailsHandler(ctx context.Context, config m
}
logrus.Info("Enabling Gitops")
gitDB := gitops.GetGitConfigDB(config)
gitDB := gitops.GetGitConfigDB(projectID, config)
gitConfig := GetGitOpsConfig(gitDB)
originalPath := gitConfig.LocalPath
@ -188,7 +188,7 @@ func (g *gitOpsService) UpdateGitOpsDetailsHandler(ctx context.Context, config m
}
gitDB.LatestCommit = commit
err = g.gitOpsOperator.ReplaceGitConfig(ctx, bson.D{{"project_id", config.ProjectID}}, &gitDB)
err = g.gitOpsOperator.ReplaceGitConfig(ctx, bson.D{{"project_id", projectID}}, &gitDB)
if err != nil {
return false, errors.New("Failed to enable GitOps in DB : " + err.Error())
}

View File

@ -18,7 +18,7 @@ type Service interface {
CreateImageRegistry(ctx context.Context, projectID string, imageRegistryInfo model.ImageRegistryInput) (*model.ImageRegistryResponse, error)
UpdateImageRegistry(ctx context.Context, imageRegistryID string, projectID string, imageRegistryInfo model.ImageRegistryInput) (*model.ImageRegistryResponse, error)
DeleteImageRegistry(ctx context.Context, imageRegistryID string, projectID string) (string, error)
GetImageRegistry(ctx context.Context, imageRegistryID string, projectID string) (*model.ImageRegistryResponse, error)
GetImageRegistry(ctx context.Context, projectID string) (*model.ImageRegistryResponse, error)
ListImageRegistries(ctx context.Context, projectID string) ([]*model.ImageRegistryResponse, error)
}
@ -86,7 +86,8 @@ func (i *imageRegistryService) CreateImageRegistry(ctx context.Context, projectI
func (i *imageRegistryService) UpdateImageRegistry(ctx context.Context, imageRegistryID string, projectID string, imageRegistryInfo model.ImageRegistryInput) (*model.ImageRegistryResponse, error) {
var (
currentTime = strconv.FormatInt(time.Now().Unix(), 10)
currentTime = time.Now().UnixMilli()
currTimeStr = strconv.FormatInt(currentTime, 10)
bl = false
)
@ -119,7 +120,7 @@ func (i *imageRegistryService) UpdateImageRegistry(ctx context.Context, imageReg
EnableRegistry: imageRegistryInfo.EnableRegistry,
IsDefault: &imageRegistryInfo.IsDefault,
},
UpdatedAt: &currentTime,
UpdatedAt: &currTimeStr,
IsRemoved: &bl,
}, nil
}
@ -136,8 +137,8 @@ func (i *imageRegistryService) DeleteImageRegistry(ctx context.Context, imageReg
return "image registry deleted", nil
}
func (i *imageRegistryService) GetImageRegistry(ctx context.Context, imageRegistryID string, projectID string) (*model.ImageRegistryResponse, error) {
query := bson.D{{"image_registry_id", imageRegistryID}, {"project_id", projectID}}
func (i *imageRegistryService) GetImageRegistry(ctx context.Context, projectID string) (*model.ImageRegistryResponse, error) {
query := bson.D{{"project_id", projectID}}
imageRegistry, err := i.imageRegistryOperator.GetImageRegistry(ctx, query)
if err != nil {
return nil, err

View File

@ -9,7 +9,6 @@ import (
"github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/database/mongodb/project"
"github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/grpc"
image_registry2 "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/image_registry"
self_deployer "github.com/litmuschaos/litmus/chaoscenter/graphql/server/pkg/self-deployer"
"github.com/sirupsen/logrus"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
@ -21,8 +20,6 @@ func ProjectInitializer(ctx context.Context, projectID string, role string, oper
var bl_true = true
self_deployer.StartDeployer(projectID, operator)
irOp := image_registry.NewImageRegistryOperator(operator)
irService := image_registry2.NewImageRegistryService(irOp)
_, err := irService.CreateImageRegistry(ctx, projectID, model.ImageRegistryInput{

View File

@ -0,0 +1,25 @@
import { gql, useMutation } from '@apollo/client';
import type { AddImageRegistryRequest, CreateImageRegistryResponse } from '@api/entities';
import type { GqlAPIMutationRequest, GqlAPIMutationResponse } from '@api/types';
export function addImageRegistry(
options?: GqlAPIMutationRequest<CreateImageRegistryResponse, AddImageRegistryRequest>
): GqlAPIMutationResponse<CreateImageRegistryResponse, AddImageRegistryRequest> {
const [addImageRegistryMutation, result] = useMutation<CreateImageRegistryResponse, AddImageRegistryRequest>(
gql`
mutation createImageRegistry($projectID: String!, $imageRegistryInfo: ImageRegistryInput!) {
createImageRegistry(projectID: $projectID, imageRegistryInfo: $imageRegistryInfo) {
imageRegistryInfo {
imageRepoName
imageRegistryName
imageRegistryType
isDefault
}
}
}
`,
options
);
return [addImageRegistryMutation, result];
}

View File

@ -0,0 +1,49 @@
import { gql, useQuery } from '@apollo/client';
import type { GetImageRegistryResponse } from '@api/entities';
import type { GqlAPIQueryRequest, GqlAPIQueryResponse } from '@api/types';
export interface GetImageRegistryRequest {
projectID: string;
}
// TODO: Update this API to latest API structure with options
export function getImageRegistry({
projectID,
options = {}
}: GqlAPIQueryRequest<GetImageRegistryResponse, GetImageRegistryRequest>): GqlAPIQueryResponse<
GetImageRegistryResponse,
GetImageRegistryRequest
> {
// Query to get chaosHub
const { data, loading, ...rest } = useQuery<GetImageRegistryResponse, GetImageRegistryRequest>(
gql`
query getImageRegistry($projectID: String!) {
getImageRegistry(projectID: $projectID) {
imageRegistryInfo {
isDefault
enableRegistry
secretName
secretNamespace
imageRegistryName
imageRepoName
imageRegistryType
}
imageRegistryID
}
}
`,
{
variables: {
projectID
},
fetchPolicy: options.fetchPolicy ?? 'cache-and-network',
...options
}
);
return {
data,
loading: loading,
...rest
};
}

View File

@ -0,0 +1 @@
export * from './getImageRegistry';

View File

@ -0,0 +1,43 @@
import { gql, useMutation } from '@apollo/client';
import type { ImageRegistry, ImageRegistryInfo } from '@api/entities';
import type { GqlAPIMutationRequest, GqlAPIMutationResponse } from '@api/types';
export interface UpdateImageRegistryRequest {
projectID: string;
imageRegistryInfo: ImageRegistryInfo;
imageRegistryID: string;
}
export interface UpdateImageRegistryResponse {
updateImageRegistry: ImageRegistry;
}
export function updateImageRegistry(
options?: GqlAPIMutationRequest<UpdateImageRegistryResponse, UpdateImageRegistryRequest>
): GqlAPIMutationResponse<UpdateImageRegistryResponse, UpdateImageRegistryRequest> {
const [updateImageRegistryMutation, result] = useMutation<UpdateImageRegistryResponse, UpdateImageRegistryRequest>(
gql`
mutation updateImageRegistry(
$imageRegistryID: String!
$projectID: String!
$imageRegistryInfo: ImageRegistryInput!
) {
updateImageRegistry(
imageRegistryID: $imageRegistryID
projectID: $projectID
imageRegistryInfo: $imageRegistryInfo
) {
imageRegistryInfo {
imageRepoName
imageRegistryName
imageRegistryType
isDefault
}
}
}
`,
options
);
return [updateImageRegistryMutation, result];
}

View File

@ -0,0 +1,18 @@
import { gql, useMutation } from '@apollo/client';
import type { GqlAPIMutationRequest, GqlAPIMutationResponse } from '@api/types';
import type { DisableGitOpsRequest } from '@api/entities/gitops';
export function disableGitOps(
options?: GqlAPIMutationRequest<boolean, DisableGitOpsRequest>
): GqlAPIMutationResponse<boolean, DisableGitOpsRequest> {
const [disableGitOpsMutation, result] = useMutation<boolean, DisableGitOpsRequest>(
gql`
mutation disableGitOps($projectID: ID!) {
disableGitOps(projectID: $projectID)
}
`,
options
);
return [disableGitOpsMutation, result];
}

View File

@ -0,0 +1,18 @@
import { gql, useMutation } from '@apollo/client';
import type { GqlAPIMutationRequest, GqlAPIMutationResponse } from '@api/types';
import type { EnableGitOpsRequest } from '@api/entities/gitops';
export function enableGitOps(
options?: GqlAPIMutationRequest<boolean, EnableGitOpsRequest>
): GqlAPIMutationResponse<boolean, EnableGitOpsRequest> {
const [enableGitOpsMutation, result] = useMutation<boolean, EnableGitOpsRequest>(
gql`
mutation enableGitOps($projectID: ID!, $configurations: GitConfig!) {
enableGitOps(projectID: $projectID, configurations: $configurations)
}
`,
options
);
return [enableGitOpsMutation, result];
}

View File

@ -0,0 +1,48 @@
import { gql, useQuery } from '@apollo/client';
import type { GqlAPIQueryRequest, GqlAPIQueryResponse } from '@api/types';
import type { GetGitOpsDetailResponse } from '@api/entities/gitops';
export interface GetGitOpsDetailsRequest {
projectID: string;
}
// TODO: Update this API to latest API structure with options
export function getGitOpsDetails({
projectID,
options = {}
}: GqlAPIQueryRequest<GetGitOpsDetailResponse, GetGitOpsDetailsRequest>): GqlAPIQueryResponse<
GetGitOpsDetailResponse,
GetGitOpsDetailsRequest
> {
// Query to get chaosHub
const { data, loading, ...rest } = useQuery<GetGitOpsDetailResponse, GetGitOpsDetailsRequest>(
gql`
query getGitOpsDetails($projectID: ID!) {
getGitOpsDetails(projectID: $projectID) {
enabled
projectID
branch
repoURL
authType
token
userName
password
sshPrivateKey
}
}
`,
{
variables: {
projectID
},
fetchPolicy: options.fetchPolicy ?? 'cache-and-network',
...options
}
);
return {
data,
loading: loading,
...rest
};
}

View File

@ -0,0 +1,4 @@
export * from './getGitops';
export * from './enableGitops';
export * from './disableGitops';
export * from './updateGitops';

View File

@ -0,0 +1,18 @@
import { gql, useMutation } from '@apollo/client';
import type { GqlAPIMutationRequest, GqlAPIMutationResponse } from '@api/types';
import type { UpdateGitOpsRequest } from '@api/entities/gitops';
export function updateGitOps(
options?: GqlAPIMutationRequest<boolean, UpdateGitOpsRequest>
): GqlAPIMutationResponse<boolean, UpdateGitOpsRequest> {
const [updateGitOpsMutation, result] = useMutation<boolean, UpdateGitOpsRequest>(
gql`
mutation updateGitOps($projectID: ID!, $configurations: GitConfig!) {
updateGitOps(projectID: $projectID, configurations: $configurations)
}
`,
options
);
return [updateGitOpsMutation, result];
}

View File

@ -0,0 +1,38 @@
export interface GitOpsConfig {
enabled: boolean;
branch: string;
repoURL: string;
authType: string;
token: string;
userName: string;
password: string;
sshPrivateKey: string;
}
export interface GitOpsConfigRequest {
branch: string;
repoURL: string;
authType: string;
token: string;
userName: string;
password: string;
sshPrivateKey: string;
}
export interface GetGitOpsDetailResponse {
getGitOpsDetails: GitOpsConfig;
}
export interface EnableGitOpsRequest {
projectID: string;
configurations: GitOpsConfigRequest;
}
export interface DisableGitOpsRequest {
projectID: string;
}
export interface UpdateGitOpsRequest {
projectID: string;
configurations: GitOpsConfigRequest;
}

View File

@ -0,0 +1,44 @@
export interface ImageRegistryInfo {
isDefault: boolean;
imageRegistryName: string;
imageRepoName: string;
imageRegistryType: ImageRegistryType;
secretName: string;
secretNamespace: string;
enableRegistry: boolean;
}
export enum ImageRegistryType {
PUBLIC = 'public',
PRIVATE = 'private'
}
export interface ImageRegistry {
imageRegistryInfo: ImageRegistryInfo;
imageRegistryID: string;
projectID: string;
updatedAt: string;
createdAt: string;
isRemoved: boolean;
}
export interface CreateImageRegistryResponse {
createImageRegistry: ImageRegistry;
}
export interface GetImageRegistryResponse {
getImageRegistry: ImageRegistry;
}
export interface ListImageRegistryResponse {
listImageRegistry: ImageRegistry[];
}
export interface UpdateImageRegistryResponse {
updateImageRegistry: ImageRegistry;
}
export interface AddImageRegistryRequest {
projectID: string;
imageRegistryInfo: ImageRegistryInfo;
}

View File

@ -6,3 +6,4 @@ export * from './workflow';
export * from './workflowRun';
export * from './stats';
export * from './environment';
export * from './imageRegistry';

View File

@ -96,6 +96,8 @@ export default function SideNav(): ReactElement {
<SidebarLink label={'Chaos Experiments'} to={paths.toExperiments()} />
<SidebarLink label={'ChaosHubs'} to={paths.toChaosHubs()} />
<SidebarLink label={'Environments'} to={paths.toEnvironments()} />
<SidebarLink label={'Gitops'} to={paths.toGitops()} />
<SidebarLink label={'Image Registry'} to={paths.toImageRegistry()} />
<SidebarLink label={'Members'} to={paths.toProjectMembers()} />
</Layout.Vertical>
</div>

View File

@ -0,0 +1,60 @@
import React from 'react';
import { useToaster } from '@harnessio/uicore';
import GitopsView from '@views/Gitops/Gitops';
import { enableGitOps, getGitOpsDetails, updateGitOps } from '@api/core/gitops';
import { getScope } from '@utils';
import { disableGitOps } from '@api/core/gitops/disableGitops';
export default function GitopsController(): React.ReactElement {
const scope = getScope();
const { showError, showSuccess } = useToaster();
const {
data: getGitOpsDetailsData,
loading: getGitOpsDetailsLoading,
refetch: getGitOpsDetailsRefetch
} = getGitOpsDetails({
projectID: scope.projectID,
options: {
onError: error => showError(error.message),
nextFetchPolicy: 'cache-first'
}
});
const [enableGitopsMutation, { loading: enableGitopsMutationLoading }] = enableGitOps({
onCompleted: () => {
showSuccess('Gitops enabled successfully');
getGitOpsDetailsRefetch();
},
onError: err => showError(err.message)
});
const [updateGitopsMutation, { loading: updateGitopsMutationLoading }] = updateGitOps({
onCompleted: () => {
showSuccess('Gitops enabled successfully');
getGitOpsDetailsRefetch();
},
onError: err => showError(err.message)
});
const [disableGitopsMutation, { loading: disableGitopsMutationLoading }] = disableGitOps({
onCompleted: () => {
showSuccess('Gitops disabled successfully');
getGitOpsDetailsRefetch();
},
onError: err => showError(err.message)
});
return (
<GitopsView
gitopsDetails={getGitOpsDetailsData?.getGitOpsDetails}
enableGitops={enableGitopsMutation}
disableGitops={disableGitopsMutation}
updateGitops={updateGitopsMutation}
loading={{
getGitOpsDetailsLoading: getGitOpsDetailsLoading,
disableGitopsMutationLoading: disableGitopsMutationLoading,
updateGitopsMutationLoading: updateGitopsMutationLoading,
enableGitopsMutationLoading: enableGitopsMutationLoading
}}
/>
);
}

View File

@ -0,0 +1,3 @@
import GitopsController from './Gitops';
export default GitopsController;

View File

@ -0,0 +1,56 @@
import React from 'react';
import { useToaster } from '@harnessio/uicore';
import { getScope } from '@utils';
import { getImageRegistry } from '@api/core/ImageRegistry';
import { addImageRegistry } from '@api/core/ImageRegistry/addImageRegistry';
import { updateImageRegistry } from '@api/core/ImageRegistry/updateImageRegistry';
import ImageRegistryView from '@views/ImageRegistry';
import { useStrings } from '@strings';
const ImageRegistryController: React.FC = () => {
const scope = getScope();
const { getString } = useStrings();
const { showError, showSuccess } = useToaster();
const {
data: getImageRegistryData,
loading: getImageRegistryLoading,
refetch: listImageRegistryRefetch
} = getImageRegistry({
projectID: scope.projectID,
options: {
onError: err => showError(err.message),
nextFetchPolicy: 'cache-first'
}
});
const [addImageRegistryMutation, { loading: addImageRegistryMutationLoading }] = addImageRegistry({
onCompleted: () => {
showSuccess(getString('imageRegistryUpdateSuccess'));
listImageRegistryRefetch();
},
onError: err => showError(err.message)
});
const [updateImageRegistryMutation, { loading: updateImageRegistryMutationLoading }] = updateImageRegistry({
onCompleted: () => {
showSuccess(getString('imageRegistryUpdateSuccess'));
listImageRegistryRefetch();
},
onError: err => showError(err.message)
});
return (
<ImageRegistryView
listImageRegistryRefetch={listImageRegistryRefetch}
imageRegistryData={getImageRegistryData?.getImageRegistry}
loading={{
getImageRegistry: getImageRegistryLoading,
addImageRegistryMutationLoading: addImageRegistryMutationLoading,
updateImageRegistryMutationLoading: updateImageRegistryMutationLoading
}}
updateImageRegistryMutation={updateImageRegistryMutation}
addImageRegistryMutation={addImageRegistryMutation}
/>
);
};
export default ImageRegistryController;

View File

@ -0,0 +1,3 @@
import ImageRegistryController from './ImageRegistry';
export default ImageRegistryController;

View File

@ -0,0 +1,4 @@
export enum GitopsValues {
LOCAL = 'local',
GITHUB = 'github'
}

View File

@ -12,3 +12,4 @@ export * from './user';
export * from './projectMembers';
export * from './token';
export * from './projects';
export * from './gitops';

View File

@ -23,6 +23,8 @@ export interface UseRouteDefinitionsProps {
toChaosInfrastructures(params: { environmentID: string }): string;
toKubernetesChaosInfrastructures(params: { environmentID: string }): string;
toKubernetesChaosInfrastructureDetails(params: { chaosInfrastructureID: string; environmentID: string }): string;
toImageRegistry(): string;
toGitops(): string;
// Project scoped
toProjectMembers(): string;
// Account Scoped Routes
@ -57,6 +59,9 @@ export const paths: UseRouteDefinitionsProps = {
toKubernetesChaosInfrastructures: ({ environmentID }) => `/environments/${environmentID}/kubernetes`,
toKubernetesChaosInfrastructureDetails: ({ chaosInfrastructureID, environmentID }) =>
`/environments/${environmentID}/kubernetes/${chaosInfrastructureID}`,
// chaos image registry routes
toImageRegistry: () => `/image-registry`,
toGitops: () => `/gitops`,
// Account Scoped Routes
toAccountSettingsOverview: () => '/settings/overview',
// user route

View File

@ -19,6 +19,8 @@ import LoginController from '@controllers/Login';
import { getUserDetails } from '@utils';
import EnvironmentController from '@controllers/Environments';
import { isUserAuthenticated } from 'utils/auth';
import ImageRegistryController from '@controllers/ImageRegistry';
import GitopsController from '@controllers/Gitops';
import AccountSettingsController from '@controllers/AccountSettings';
import ProjectMembersView from '@views/ProjectMembers';
@ -108,6 +110,8 @@ export function RoutesWithAuthentication(): React.ReactElement {
path={projectMatchPaths.toKubernetesChaosInfrastructureDetails({ environmentID, chaosInfrastructureID })}
component={KubernetesChaosInfrastructureDetailsController}
/>
<Route exact path={projectMatchPaths.toImageRegistry()} component={ImageRegistryController} />
<Route exact path={projectMatchPaths.toGitops()} component={GitopsController} />
{/* Project */}
<Route exact path={projectMatchPaths.toProjectMembers()} component={ProjectMembersView} />
</Switch>

View File

@ -14,6 +14,8 @@ aboutChaosCTL: >-
infrastructure:
acceptInvitation: Accept Invitation
accessToAllNamespaces: Access to all namespaces
accessToken: Access Token
accessTokenPlaceholder: Enter your Personal Access Token
accessType: Access Type
account: Account
accountURL: Account URL
@ -64,6 +66,7 @@ blankCanvasDescription: >-
experiment.
blankCanvasTitle: Select and arrange faults from ChaosHubs to create your desire sequence.
blobLogsNotAvailable: Logs are not available for this node.
branch: Branch
cancel: Cancel
cannotPushToDefault: Cannot push experiment to default ChaosHub
cannotReRun: Cannot re-run an already running experiment
@ -197,7 +200,11 @@ cronText: >-
can stop the schedule anytime you want.
currentRun: Current Run
currentUTCTime: Current UTC Time
customImageRegistry: Custom Image Registry
customLabel: Custom
customRepo: Custom Repo
customValueText: All YAML files will use the custom values.
customValues: Use Custom Values
daily: Daily
dailyMessage: Your chaos experiment will run daily at your chosen time.
dateExecuted: Date Executed
@ -205,6 +212,10 @@ dayOfMonthLabel: Day of month
dayOfWeekLabel: Day of week
declineInvitation: Decline Invitation
declineInvitationDescription: Are you sure you want to decline the invitation?
defaultValueOption: Use Default Values
defaultValueText: >-
All YAML files use these default values provided by Litmus. These values
cannot be changed.
degelateNotActive: Selected infrastructure is inactive. Please select an active one.
delete: Delete
deleteChaosInfrastructure: Are you sure you want to disable this Chaos Infrastructure?
@ -237,6 +248,7 @@ discardExperiment: Are you sure you want to discard the current experiment?
disconnectDescriptionClusterMode: Disable Chaos for this cluster.
disconnectDescriptionNamespaceMode: Disable Chaos for this namespace.
disconnected: Disconnected
docker: docker.io
done: Done
download: Download
downloadChaosInfrastructureManifest: Re-Download the manifest
@ -365,10 +377,13 @@ featureRestriction:
You have exceeded your resource subscription limit. Consider increasing your
limits to keep shipping.
fieldSelector: Field Selector
generateSSH: Generate New SSH Key
genericResourceNotFoundError: >-
{{resource}} [{{resourceID}}] under Project [{{projectID}}] does not exist or
has been deleted.
gitConnection: Repository Connection
githubRepo: Github Repository
gitops: Gitops
goBack: Go back to previous page
goChaosHome: Go to Home
greatJob: Great Job
@ -402,6 +417,10 @@ hubRepositoryBranch: Hub Repository Branch
hubRepositoryURL: Repository URL
id: ID
idlowerCase: id
imageRegistry: Image Registry
imageRegistryUpdateSuccess: Image Registry added successfully
imageSecret: Image Secret
imageSecretPlaceholder: Enter your Image Secret
improveResilienceOfTheDeployedService: Improve resilience of the deployed service
inactive: Inactive
inactiveTooltip: >-
@ -480,7 +499,9 @@ leaveProjectDescription: Are you sure you want to leave the project?
letsGetStarted: Let`s get started
litmus: Litmus
litmusChaos: LitmusChaos
litmuschaos: litmuschaos
loading: Loading, please wait...
local: Locally in Litmus
logErrorMessage: Unable to fetch logs from log service, please try after some time.
loginDescription: Login to create, orchestrate, analyze and collaborate your Chaos Experiments.
loginToContinue: login to continue
@ -758,10 +779,15 @@ recentlyUsed: Recently Used
recurringRun: Recurring Run (Cron)
recurringSchedule: Recurring Schedule
referencedBy: Referenced By
registry: Registry
registryName: Registry Name
registryType: Registry Type
remove: Remove
removeMember: Remove Member
removeMemberConfirmation: Are you sure you want to remove {{username}}?
repoBranchPlaceholder: Enter repository branch
repoURLPlaceholder: Enter repository URL
repository: Repository
required: Required
rerun: Rerun
resend: Resend
@ -833,6 +859,7 @@ searchForHub: Search for a hub
searchForMonitoredServices: Search for a monitored service
searchHub: Search for a Hub
secret: Secret
securityKeyType: Select Security Key Type
seeAllChaosHubs: See All ChaosHubs
seeAllChaosInfrastructures: See All Infrastructures
seeAllEnvironments: See All Environments
@ -875,6 +902,9 @@ signOut: Sign Out
singleRun: Single Run
source: Source
specificNamespaceAccess: Specific namespace access
ssh: SSH
sshKey: SSH Key
sshKeyHelper: Please make sure you copy the SSH key and save it safely.
stages: Stages
startBlankCanvasDescription: Start from scratch
startBlankCanvasTitle: Blank Canvas

View File

@ -17,6 +17,8 @@ export interface StringsMap {
'aboutChaosCTL': unknown
'acceptInvitation': unknown
'accessToAllNamespaces': unknown
'accessToken': unknown
'accessTokenPlaceholder': unknown
'accessType': unknown
'account': unknown
'accountURL': unknown
@ -61,6 +63,7 @@ export interface StringsMap {
'blankCanvasDescription': unknown
'blankCanvasTitle': unknown
'blobLogsNotAvailable': unknown
'branch': unknown
'cancel': unknown
'cannotPushToDefault': unknown
'cannotReRun': unknown
@ -163,7 +166,11 @@ export interface StringsMap {
'cronText': unknown
'currentRun': unknown
'currentUTCTime': unknown
'customImageRegistry': unknown
'customLabel': unknown
'customRepo': unknown
'customValueText': unknown
'customValues': unknown
'daily': unknown
'dailyMessage': unknown
'dateExecuted': unknown
@ -171,6 +178,8 @@ export interface StringsMap {
'dayOfWeekLabel': unknown
'declineInvitation': unknown
'declineInvitationDescription': unknown
'defaultValueOption': unknown
'defaultValueText': unknown
'degelateNotActive': unknown
'delete': unknown
'deleteChaosInfrastructure': unknown
@ -198,6 +207,7 @@ export interface StringsMap {
'disconnectDescriptionClusterMode': unknown
'disconnectDescriptionNamespaceMode': unknown
'disconnected': unknown
'docker': unknown
'done': unknown
'download': unknown
'downloadChaosInfrastructureManifest': unknown
@ -307,8 +317,11 @@ export interface StringsMap {
'featureRestriction.resourceLevelUpTeam': PrimitiveObject<'resourceLimit'>
'featureRestriction.resourceOveruseEnterprise': unknown
'fieldSelector': unknown
'generateSSH': unknown
'genericResourceNotFoundError': PrimitiveObject<'resource' | 'resourceID' | 'projectID'>
'gitConnection': unknown
'githubRepo': unknown
'gitops': unknown
'goBack': unknown
'goChaosHome': unknown
'greatJob': unknown
@ -336,6 +349,10 @@ export interface StringsMap {
'hubRepositoryURL': unknown
'id': unknown
'idlowerCase': unknown
'imageRegistry': unknown
'imageRegistryUpdateSuccess': unknown
'imageSecret': unknown
'imageSecretPlaceholder': unknown
'improveResilienceOfTheDeployedService': unknown
'inactive': unknown
'inactiveTooltip': unknown
@ -393,7 +410,9 @@ export interface StringsMap {
'letsGetStarted': unknown
'litmus': unknown
'litmusChaos': unknown
'litmuschaos': unknown
'loading': unknown
'local': unknown
'logErrorMessage': unknown
'loginDescription': unknown
'loginToContinue': unknown
@ -630,10 +649,15 @@ export interface StringsMap {
'recurringRun': unknown
'recurringSchedule': unknown
'referencedBy': unknown
'registry': unknown
'registryName': unknown
'registryType': unknown
'remove': unknown
'removeMember': unknown
'removeMemberConfirmation': PrimitiveObject<'username'>
'repoBranchPlaceholder': unknown
'repoURLPlaceholder': unknown
'repository': unknown
'required': unknown
'rerun': unknown
'resend': unknown
@ -700,6 +724,7 @@ export interface StringsMap {
'searchForMonitoredServices': unknown
'searchHub': unknown
'secret': unknown
'securityKeyType': unknown
'seeAllChaosHubs': unknown
'seeAllChaosInfrastructures': unknown
'seeAllEnvironments': unknown
@ -740,6 +765,9 @@ export interface StringsMap {
'singleRun': unknown
'source': unknown
'specificNamespaceAccess': unknown
'ssh': unknown
'sshKey': unknown
'sshKeyHelper': unknown
'stages': unknown
'startBlankCanvasDescription': unknown
'startBlankCanvasTitle': unknown

View File

@ -0,0 +1,16 @@
/**
* @description This function removes the __typename data field from response object
* @remarks Use this only and only when when the apollo response is used directly/stringified or put into idb
*/
export function cleanApolloResponse(responseWithTypeName: object): object {
return JSON.parse(
JSON.stringify(responseWithTypeName, (name, val) => {
if (name === '__typename') {
delete val[name];
} else {
return val;
}
})
);
}

View File

@ -20,3 +20,4 @@ export * from './getInfrastructureTypeFromExperimentKind';
export * from './faultTunableForm';
export * from './isOnPrem';
export * from './usePermissions';
export * from './data';

View File

@ -0,0 +1,135 @@
.subCard {
background: rgba(250, 251, 252, 1);
gap: 0.25rem;
width: 100%;
}
.radioButton {
width: 60%;
min-width: 900px;
:global {
.RadioButton--radio {
height: auto;
// width: 900px;
background: var(--white) !important;
box-shadow: 0px 0px 2px rgba(40, 41, 61, 0.04), 0px 4px 8px rgba(96, 97, 112, 0.16);
border-radius: 4px;
padding: 1.5rem 1.5rem !important;
margin-bottom: 1rem;
}
.RadioButton--radioIcon {
margin-top: 2px;
}
.bp3-form-group {
width: 100% !important;
}
}
}
.subRadioBtn {
width: 100%;
:global {
.RadioButton--radio {
height: auto;
width: auto;
background: none !important;
box-shadow: none;
border-radius: 0;
padding: 0 !important;
margin-bottom: 0;
}
.RadioButton--radioIcon {
margin-top: 0px;
}
}
}
.formContainer {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 1rem;
}
.textInputContainer {
:global {
.bp3-input-action {
height: 100% !important;
right: 5px !important;
}
}
}
.inputGroup {
display: flex;
flex-flow: column;
margin-bottom: var(--spacing-4);
:global(.bp3-input) {
display: block;
border: 1px solid var(--grey-200);
border-radius: var(--spacing-2);
font-size: var(--form-input-font-size);
padding: var(--spacing-small);
height: var(--spacing-8);
color: var(--black);
box-shadow: none;
&:hover {
border-color: var(--primary-6);
box-shadow: 0px 0px 1px rgba(40, 41, 61, 0.04), 0px 2px 4px rgba(96, 97, 112, 0.16);
}
&:focus {
color: var(--black);
border-color: var(--primary-7);
box-shadow: none;
}
&::-moz-placeholder,
&::-webkit-input-placeholder,
&:-ms-input-placeholder,
&:-moz-placeholder,
&::placeholder {
color: var(--form-placeholder-text) !important;
}
&:disabled {
background-color: var(--grey-50);
}
}
&.hasError {
:global(.bp3-input) {
border-color: var(--red-600);
&:focus {
border-color: var(--red-600);
outline-color: var(--red-600);
}
}
&.errorIcon :global(.bp3-icon:first-child) {
color: var(--red-600);
}
}
&.success {
:global(.bp3-input-action) {
margin: var(--spacing-small);
display: flex;
width: var(--spacing-4);
height: var(--spacing-4);
:global(.bp3-icon) {
display: flex;
& path {
fill: var(--green-500);
}
}
}
}
:global(.bp3-input-group > .bp3-icon:first-child) {
margin: var(--spacing-small);
}
}

View File

@ -0,0 +1,17 @@
declare namespace GitopsModuleScssNamespace {
export interface IGitopsModuleScss {
errorIcon: string;
formContainer: string;
hasError: string;
inputGroup: string;
radioButton: string;
subCard: string;
subRadioBtn: string;
success: string;
textInputContainer: string;
}
}
declare const GitopsModuleScssModule: GitopsModuleScssNamespace.IGitopsModuleScss;
export = GitopsModuleScssModule;

View File

@ -0,0 +1,338 @@
import {
Button,
ButtonVariation,
Text,
Layout,
Container,
RadioButtonGroup,
FormInput,
useToaster
} from '@harnessio/uicore';
import React, { FormEvent } from 'react';
import { Color, FontVariation } from '@harnessio/design-system';
import { Form, Formik, FormikProps } from 'formik';
import { Icon } from '@harnessio/icons';
import type { MutationFunction } from '@apollo/client';
import { useHistory, useParams } from 'react-router-dom';
import { InputGroup } from '@blueprintjs/core';
import DefaultLayout from '@components/DefaultLayout';
import RbacButton from '@components/RbacButton';
import { GitopsValues, PermissionGroup } from '@models';
import { AuthType } from '@api/entities';
import CopyButton from '@components/CopyButton';
import { generateSSHKey } from '@api/core/chaoshubs/generateSSH';
import type {
DisableGitOpsRequest,
EnableGitOpsRequest,
GitOpsConfig,
UpdateGitOpsRequest
} from '@api/entities/gitops';
import { useRouteWithBaseUrl } from '@hooks';
import { useStrings } from '@strings';
import Loader from '@components/Loader';
import css from './Gitops.module.scss';
interface GitopsData {
branch: string;
repoURL: string;
authType: AuthType;
token?: string;
sshPrivateKey?: string;
userName?: string;
password?: string;
}
interface GitopsViewProps {
gitopsDetails: GitOpsConfig | undefined;
enableGitops: MutationFunction<boolean, EnableGitOpsRequest>;
updateGitops: MutationFunction<boolean, UpdateGitOpsRequest>;
disableGitops: MutationFunction<boolean, DisableGitOpsRequest>;
loading: {
getGitOpsDetailsLoading: boolean;
enableGitopsMutationLoading: boolean;
updateGitopsMutationLoading: boolean;
disableGitopsMutationLoading: boolean;
};
}
export default function GitopsView({
gitopsDetails,
enableGitops,
disableGitops,
updateGitops,
loading
}: GitopsViewProps): React.ReactElement {
const [sshPublicKey, setPublicSshKey] = React.useState<string>('');
const [gitopsType, setGitopstype] = React.useState<GitopsValues>(
gitopsDetails?.enabled ? GitopsValues.GITHUB : GitopsValues.LOCAL
);
const { getString } = useStrings();
const initialValues: GitopsData = {
branch: gitopsDetails?.branch ?? '',
repoURL: gitopsDetails?.repoURL ?? '',
authType: (gitopsDetails?.authType as AuthType) ?? AuthType.TOKEN,
token: gitopsDetails?.token ?? '',
sshPrivateKey: gitopsDetails?.sshPrivateKey ?? ''
};
const { showError } = useToaster();
const [generateSSHKeyMutation] = generateSSHKey({
onError: error => showError(error.message)
});
const { projectID } = useParams<{ projectID: string }>();
const history = useHistory();
const paths = useRouteWithBaseUrl();
const formikRef: React.Ref<FormikProps<GitopsData>> = React.useRef(null);
function handleSubmit(values: GitopsData): void {
if (gitopsDetails?.enabled) {
if (gitopsType === GitopsValues.LOCAL) {
disableGitops({ variables: { projectID: projectID } });
} else {
values &&
updateGitops({
variables: {
projectID: projectID,
configurations: {
branch: values.branch,
repoURL: values.repoURL,
authType: values.authType,
token: values.token ?? '',
sshPrivateKey: values.sshPrivateKey ?? '',
userName: values.userName ?? '',
password: values.password ?? ''
}
}
});
}
} else {
if (gitopsType === GitopsValues.GITHUB) {
values &&
enableGitops({
variables: {
projectID: projectID,
configurations: {
branch: values.branch,
repoURL: values.repoURL,
authType: values.authType,
token: values.token ?? '',
sshPrivateKey: values.sshPrivateKey ?? '',
userName: values.userName ?? '',
password: values.password ?? ''
}
}
});
}
}
}
return (
<DefaultLayout
headerToolbar={
<Layout.Horizontal flex={{ distribution: 'space-between' }} width="12%">
<RbacButton
intent="primary"
data-testid="gitops"
iconProps={{ size: 10 }}
text={getString('save')}
permission={PermissionGroup.EDITOR}
loading={
loading.disableGitopsMutationLoading ||
loading.enableGitopsMutationLoading ||
loading.updateGitopsMutationLoading
}
onClick={() => formikRef.current?.handleSubmit()}
/>
<Button
disabled={false}
variation={ButtonVariation.SECONDARY}
text={getString('discard')}
onClick={() => history.push(paths.toDashboard())}
/>
</Layout.Horizontal>
}
title={getString('gitops')}
breadcrumbs={[]}
>
<Loader loading={loading.getGitOpsDetailsLoading}>
<Container
padding={{ top: 'medium', right: 'xlarge', left: 'xlarge' }}
height="100%"
style={{ overflowY: 'auto' }}
>
<Formik<GitopsData>
initialValues={initialValues}
onSubmit={values => handleSubmit(values)}
innerRef={formikRef}
>
{formikProps => {
return (
<Form className={css.formContainer}>
<RadioButtonGroup
name="type"
inline={false}
selectedValue={gitopsType}
className={css.radioButton}
options={[
{
label: (
<Layout.Vertical style={{ gap: '1rem' }}>
<Text
font={{ variation: FontVariation.BODY2_SEMI, weight: 'semi-bold' }}
color={Color.BLACK}
>
{getString('local')}
</Text>
</Layout.Vertical>
),
value: GitopsValues.LOCAL
},
{
label: (
<Layout.Vertical style={{ gap: '0.5rem' }} width={'60%'}>
<Layout.Vertical style={{ gap: '0.25rem' }}>
<Text
font={{ variation: FontVariation.BODY2_SEMI, weight: 'semi-bold' }}
color={Color.BLACK}
>
{getString('githubRepo')}
</Text>
</Layout.Vertical>
{gitopsType === GitopsValues.GITHUB && (
<Layout.Vertical
flex={{ justifyContent: 'flex-start', alignItems: 'flex-start' }}
className={css.subCard}
>
<FormInput.Text
name="repoURL"
label={
<Text font={{ variation: FontVariation.FORM_LABEL }} margin={{ top: 'medium' }}>
{getString('hubRepositoryURL')}
</Text>
}
placeholder={getString('repoURLPlaceholder')}
/>
<FormInput.Text
name="branch"
label={
<Text font={{ variation: FontVariation.FORM_LABEL }}>{getString('branch')}</Text>
}
placeholder={getString('repoBranchPlaceholder')}
/>
<RadioButtonGroup
name="authType"
selectedValue={initialValues.authType ?? AuthType.TOKEN}
label={
<Text font={{ variation: FontVariation.FORM_LABEL }}>
{getString('securityKeyType')}
</Text>
}
inline={true}
className={css.subRadioBtn}
onChange={(e: FormEvent<HTMLInputElement>) => {
formikProps.setFieldValue('authType', e.currentTarget.value);
}}
options={[
{
label: (
<Text font={{ variation: FontVariation.FORM_LABEL }}>
{getString('accessToken')}
</Text>
),
value: AuthType.TOKEN
},
{
label: (
<Text font={{ variation: FontVariation.FORM_LABEL }}>{getString('ssh')}</Text>
),
value: AuthType.SSH
}
]}
/>
{formikProps.values.authType === AuthType.TOKEN && (
<FormInput.Text
name="token"
label={
<Text font={{ variation: FontVariation.FORM_LABEL }} margin={{ top: 'medium' }}>
{getString('accessToken')}
</Text>
}
placeholder={getString('accessTokenPlaceholder')}
/>
)}
{formikProps.values.authType === AuthType.SSH && (
<Layout.Vertical
spacing={'small'}
flex={{ justifyContent: 'flex-start', alignItems: 'flex-start' }}
>
<Button
onClick={() => {
generateSSHKeyMutation({
onCompleted: data => {
setPublicSshKey(data.generateSSHKey.publicKey);
formikProps.setFieldValue('sshPrivateKey', data.generateSSHKey.privateKey);
formikProps.setFieldValue('sshPublicKey', data.generateSSHKey.publicKey);
}
});
}}
variation={ButtonVariation.SECONDARY}
text={getString('generateSSH')}
/>
<div className={css.textInputContainer}>
<Text
font={{ variation: FontVariation.FORM_LABEL }}
margin={{ bottom: 'xsmall' }}
>
{getString('sshKey')}
</Text>
<div className={css.inputGroup}>
<InputGroup
type="text"
placeholder={getString('sshKey')}
value={sshPublicKey}
onChange={(e: FormEvent<HTMLInputElement>) => {
setPublicSshKey(e.currentTarget.value);
formikProps.setFieldValue('sshPublicKey', e.currentTarget.value);
}}
rightElement={
<Container
margin={{ left: 'small', right: 'xsmall' }}
flex={{ justifyContent: 'center', alignItems: 'center' }}
height="100%"
>
<CopyButton stringToCopy={sshPublicKey} />
</Container>
}
/>
</div>
<Layout.Horizontal spacing={'xsmall'} flex={{ alignItems: 'center' }}>
<Icon name="info-message" size={15} />
<Text font={{ variation: FontVariation.SMALL }}>
{getString('sshKeyHelper')}
</Text>
</Layout.Horizontal>
</div>
</Layout.Vertical>
)}
</Layout.Vertical>
)}
</Layout.Vertical>
),
value: GitopsValues.GITHUB
}
]}
onChange={(e: FormEvent<HTMLInputElement>) => {
setGitopstype(e.currentTarget.value as GitopsValues);
}}
/>
</Form>
);
}}
</Formik>
</Container>
</Loader>
</DefaultLayout>
);
}

View File

@ -0,0 +1,51 @@
.subCard {
background: rgba(250, 251, 252, 1);
gap: 0.25rem;
}
.radioButton {
width: 60%;
min-width: 900px;
:global {
.RadioButton--radio {
height: auto;
// width: 900px;
background: var(--white) !important;
box-shadow: 0px 0px 2px rgba(40, 41, 61, 0.04), 0px 4px 8px rgba(96, 97, 112, 0.16);
border-radius: 4px;
padding: 1.5rem 1.5rem !important;
margin-bottom: 1rem;
}
.RadioButton--radioIcon {
margin-top: 2px;
}
.bp3-form-group {
width: 100% !important;
}
}
}
.subRadioBtn {
width: 100%;
:global {
.RadioButton--radio {
height: auto;
width: auto;
background: none !important;
box-shadow: none;
border-radius: 0;
padding: 0 !important;
margin-bottom: 0;
}
.RadioButton--radioIcon {
margin-top: 0px;
}
}
}
.formContainer {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 1rem;
}

View File

@ -0,0 +1,12 @@
declare namespace ImageRegistryModuleScssNamespace {
export interface IImageRegistryModuleScss {
formContainer: string;
radioButton: string;
subCard: string;
subRadioBtn: string;
}
}
declare const ImageRegistryModuleScssModule: ImageRegistryModuleScssNamespace.IImageRegistryModuleScss;
export = ImageRegistryModuleScssModule;

View File

@ -0,0 +1,281 @@
import { Button, ButtonVariation, Text, Layout, Container, RadioButtonGroup, FormInput } from '@harnessio/uicore';
import React, { FormEvent } from 'react';
import { Color, FontVariation } from '@harnessio/design-system';
import type { ApolloQueryResult, MutationFunction } from '@apollo/client';
import { useHistory, useParams } from 'react-router-dom';
import { Form, FormikProps, Formik } from 'formik';
import { defaultTo } from 'lodash-es';
import DefaultLayout from '@components/DefaultLayout';
import RbacButton from '@components/RbacButton';
import { PermissionGroup } from '@models';
import {
AddImageRegistryRequest,
CreateImageRegistryResponse,
GetImageRegistryResponse,
ImageRegistry,
ImageRegistryInfo,
ImageRegistryType,
UpdateImageRegistryResponse
} from '@api/entities';
import type { GetImageRegistryRequest } from '@api/core/ImageRegistry';
import type { UpdateImageRegistryRequest } from '@api/core/ImageRegistry/updateImageRegistry';
import { useRouteWithBaseUrl } from '@hooks';
import { useStrings } from '@strings';
import Loader from '@components/Loader';
import { cleanApolloResponse } from '@utils';
import css from './ImageRegistry.module.scss';
interface ImageRegistryViewProps {
imageRegistryData: ImageRegistry | undefined;
addImageRegistryMutation: MutationFunction<CreateImageRegistryResponse, AddImageRegistryRequest>;
updateImageRegistryMutation: MutationFunction<UpdateImageRegistryResponse, UpdateImageRegistryRequest>;
listImageRegistryRefetch: (
variables?: Partial<GetImageRegistryRequest> | undefined
) => Promise<ApolloQueryResult<GetImageRegistryResponse>>;
loading: {
getImageRegistry: boolean;
addImageRegistryMutationLoading: boolean;
updateImageRegistryMutationLoading: boolean;
};
}
export default function ImageRegistryView({
imageRegistryData,
addImageRegistryMutation,
updateImageRegistryMutation,
loading
}: ImageRegistryViewProps): React.ReactElement {
const { getString } = useStrings();
const history = useHistory();
const paths = useRouteWithBaseUrl();
const { projectID } = useParams<{ projectID: string }>();
const defaultImageRegistryInfo: ImageRegistryInfo = {
isDefault: true,
imageRegistryName: 'docker.io',
imageRepoName: 'litmuschaos',
imageRegistryType: ImageRegistryType.PUBLIC,
secretName: '',
secretNamespace: '',
enableRegistry: false
};
const initialValues: ImageRegistryInfo = cleanApolloResponse(
defaultTo(imageRegistryData?.imageRegistryInfo, defaultImageRegistryInfo)
) as ImageRegistryInfo;
const formikRef: React.Ref<FormikProps<ImageRegistryInfo>> = React.useRef(null);
function handleSubmit(values: ImageRegistryInfo): void {
const payload = values.isDefault
? { ...defaultImageRegistryInfo, enableRegistry: true }
: { ...values, enableRegistry: true };
imageRegistryData
? updateImageRegistryMutation({
variables: {
projectID: projectID,
imageRegistryID: imageRegistryData.imageRegistryID,
imageRegistryInfo: payload
}
})
: addImageRegistryMutation({
variables: {
projectID: projectID,
imageRegistryInfo: payload
}
});
}
return (
<DefaultLayout
headerToolbar={
<Layout.Horizontal flex={{ distribution: 'space-between' }} width="12%">
<RbacButton
intent="primary"
data-testid="save-image-registry"
iconProps={{ size: 10 }}
text={getString('save')}
loading={
imageRegistryData ? loading.updateImageRegistryMutationLoading : loading.addImageRegistryMutationLoading
}
permission={PermissionGroup.EDITOR}
onClick={() => formikRef.current?.handleSubmit()}
/>
<Button
disabled={false}
variation={ButtonVariation.SECONDARY}
text={getString('discard')}
onClick={() => history.push(paths.toDashboard())}
/>
</Layout.Horizontal>
}
title={getString('imageRegistry')}
breadcrumbs={[]}
>
<Loader loading={loading.getImageRegistry}>
<Container
padding={{ top: 'medium', right: 'xlarge', left: 'xlarge' }}
height="100%"
style={{ overflowY: 'auto' }}
>
<Formik<ImageRegistryInfo>
initialValues={initialValues}
onSubmit={values => handleSubmit(values)}
innerRef={formikRef}
enableReinitialize
>
{formikProps => {
return (
<Form className={css.formContainer}>
<RadioButtonGroup
className={css.radioButton}
selectedValue={formikProps.initialValues.isDefault.toString()}
onChange={(e: FormEvent<HTMLInputElement>) => {
formikProps.setFieldValue('isDefault', e.currentTarget.value === 'true' ? true : false);
}}
options={[
{
label: (
<Layout.Vertical style={{ gap: '1rem' }}>
<Layout.Vertical style={{ gap: '0.25rem' }}>
<Text
font={{ variation: FontVariation.BODY2_SEMI, weight: 'semi-bold' }}
color={Color.BLACK}
>
{getString('defaultValueOption')}
</Text>
<Text font={{ size: 'small' }}>{getString('defaultValueText')}</Text>
</Layout.Vertical>
{formikProps.values.isDefault === true && (
<Layout.Horizontal
flex={{ justifyContent: 'flex-start', alignItems: 'flex-start' }}
className={css.subCard}
>
<Layout.Vertical margin={{ right: 'huge' }}>
<Text font={{ variation: FontVariation.BODY }} color={Color.GREY_600}>
{getString('registry')}:
</Text>
<Text font={{ variation: FontVariation.BODY, weight: 'semi-bold' }}>
{defaultImageRegistryInfo.imageRegistryName}
</Text>
</Layout.Vertical>
<Layout.Vertical margin={{ right: 'huge' }}>
<Text font={{ variation: FontVariation.BODY }} color={Color.GREY_600}>
{getString('repository')}:
</Text>
<Text font={{ variation: FontVariation.BODY, weight: 'semi-bold' }}>
{defaultImageRegistryInfo.imageRepoName}
</Text>
</Layout.Vertical>
<Layout.Vertical>
<Text font={{ variation: FontVariation.BODY }} color={Color.GREY_600}>
{getString('registryType')}:
</Text>
<Text font={{ variation: FontVariation.BODY, weight: 'semi-bold' }}>
{defaultImageRegistryInfo.imageRegistryType}
</Text>
</Layout.Vertical>
</Layout.Horizontal>
)}
</Layout.Vertical>
),
value: 'true'
},
{
label: (
<Layout.Vertical style={{ gap: '0.5rem' }}>
<Layout.Vertical style={{ gap: '0.25rem' }}>
<Text
font={{ variation: FontVariation.BODY2_SEMI, weight: 'semi-bold' }}
color={Color.BLACK}
>
{getString('customValues')}
</Text>
<Text font={{ size: 'small' }}>{getString('customValueText')}</Text>
</Layout.Vertical>
{formikProps.values.isDefault === false && (
<Layout.Vertical
flex={{ justifyContent: 'flex-start', alignItems: 'flex-start' }}
className={css.subCard}
>
<FormInput.Text
name="imageRegistryName"
label={
<Text font={{ variation: FontVariation.FORM_LABEL }} margin={{ top: 'small' }}>
{getString('customImageRegistry')}
</Text>
}
placeholder={getString('name')}
/>
<FormInput.Text
name="imageRepoName"
label={
<Text font={{ variation: FontVariation.FORM_LABEL }}>
{getString('customRepo')}
</Text>
}
placeholder={getString('hubRepositoryURL')}
/>
<RadioButtonGroup
name="imageRegistryType"
label={
<Text font={{ variation: FontVariation.FORM_LABEL }}>
{getString('registryType')}
</Text>
}
selectedValue={initialValues.imageRegistryType}
inline={true}
className={css.subRadioBtn}
onChange={(e: FormEvent<HTMLInputElement>) => {
formikProps.setFieldValue('imageRegistryType', e.currentTarget.value);
}}
options={[
{
label: (
<Text font={{ variation: FontVariation.FORM_LABEL }}>
{getString('public')}
</Text>
),
value: ImageRegistryType.PUBLIC
},
{
label: (
<Text font={{ variation: FontVariation.FORM_LABEL }}>
{getString('private')}
</Text>
),
value: ImageRegistryType.PRIVATE
}
]}
/>
{formikProps.values.imageRegistryType === ImageRegistryType.PRIVATE && (
<Layout.Vertical width={'100%'}>
<FormInput.Text
name="secretName"
label={
<Text font={{ variation: FontVariation.FORM_LABEL }} margin={{ top: 'medium' }}>
{getString('imageSecret')}
</Text>
}
placeholder={getString('imageSecretPlaceholder')}
/>
</Layout.Vertical>
)}
</Layout.Vertical>
)}
</Layout.Vertical>
),
value: 'false'
}
]}
/>
</Form>
);
}}
</Formik>
</Container>
</Loader>
</DefaultLayout>
);
}

View File

@ -0,0 +1,3 @@
import ImageRegistryView from './ImageRegistry';
export default ImageRegistryView;