mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-12 09:33:41 +00:00
Merge branch 'main' into grcp-server-reflect
This commit is contained in:
commit
f011882b2d
@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
branches: [
|
||||
{name: 'main'},
|
||||
{name: '1.87.x', range: '1.87.x', channel: '1.87.x'}
|
||||
{name: 'next'},
|
||||
],
|
||||
plugins: [
|
||||
"@semantic-release/commit-analyzer"
|
||||
|
@ -16,11 +16,11 @@ ENV PROTOC_ARCH x86_64
|
||||
## protoc and protoc-gen-grpc-web for later use
|
||||
#######################
|
||||
FROM ${BUILDARCH}-base
|
||||
ARG PROTOC_VERSION=3.18.0
|
||||
ARG PROTOC_VERSION=22.3
|
||||
ARG PROTOC_ZIP=protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip
|
||||
ARG GRPC_WEB_VERSION=1.3.0
|
||||
ARG GATEWAY_VERSION=2.15.1
|
||||
ARG VALIDATOR_VERSION=0.6.2
|
||||
ARG GATEWAY_VERSION=2.15.2
|
||||
ARG VALIDATOR_VERSION=0.10.1
|
||||
# no arm specific version available and x86 works fine at the moment:
|
||||
ARG GRPC_WEB=protoc-gen-grpc-web-${GRPC_WEB_VERSION}-linux-x86_64
|
||||
|
||||
|
@ -73,7 +73,6 @@ COPY --from=go-stub /go/src/github.com/zitadel/zitadel/openapi/statik/statik.go
|
||||
COPY --from=go-stub /go/src/github.com/zitadel/zitadel/pkg/grpc pkg/grpc
|
||||
COPY --from=go-stub /go/src/github.com/zitadel/zitadel/openapi/v2/zitadel openapi/v2/zitadel
|
||||
COPY --from=go-stub /go/src/github.com/zitadel/zitadel/openapi/statik/statik.go openapi/statik/statik.go
|
||||
COPY --from=go-stub /go/src/github.com/zitadel/zitadel/internal/protoc/protoc-gen-authoption/templates.gen.go internal/protoc/protoc-gen-authoption/templates.gen.go
|
||||
COPY --from=go-stub /go/src/github.com/zitadel/zitadel/internal/protoc/protoc-gen-authoption/authoption/options.pb.go internal/protoc/protoc-gen-authoption/authoption/options.pb.go
|
||||
COPY --from=go-stub /go/src/github.com/zitadel/zitadel/docs/apis/proto docs/docs/apis/proto
|
||||
COPY --from=go-stub /go/src/github.com/zitadel/zitadel/docs/apis/assets docs/docs/apis/assets
|
||||
|
@ -15,17 +15,11 @@ protoc \
|
||||
-I=/proto/include/ \
|
||||
--go_out $GOPATH/src \
|
||||
--go-grpc_out $GOPATH/src \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
$(find ${PROTO_PATH} -iname *.proto)
|
||||
|
||||
# generate authoptions code from templates
|
||||
go-bindata \
|
||||
-pkg main \
|
||||
-prefix internal/protoc/protoc-gen-authoption \
|
||||
-o ${ZITADEL_PATH}/internal/protoc/protoc-gen-authoption/templates.gen.go \
|
||||
${ZITADEL_PATH}/internal/protoc/protoc-gen-authoption/templates
|
||||
|
||||
# install authoption proto compiler
|
||||
go install ${ZITADEL_PATH}/internal/protoc/protoc-gen-authoption
|
||||
go install ${ZITADEL_PATH}/internal/protoc/protoc-gen-auth
|
||||
|
||||
# output folder for openapi v2
|
||||
mkdir -p ${OPENAPI_PATH}
|
||||
@ -39,28 +33,20 @@ protoc \
|
||||
--grpc-gateway_opt logtostderr=true \
|
||||
--openapiv2_out ${OPENAPI_PATH} \
|
||||
--openapiv2_opt logtostderr=true \
|
||||
--authoption_out ${GRPC_PATH}/system \
|
||||
--auth_out ${GOPATH}/src \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
${PROTO_PATH}/system.proto
|
||||
|
||||
# authoptions are generated into the wrong folder
|
||||
mv ${ZITADEL_PATH}/pkg/grpc/system/zitadel/* ${ZITADEL_PATH}/pkg/grpc/system
|
||||
rm -r ${ZITADEL_PATH}/pkg/grpc/system/zitadel
|
||||
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--grpc-gateway_out ${GOPATH}/src \
|
||||
--grpc-gateway_opt logtostderr=true \
|
||||
--openapiv2_out ${OPENAPI_PATH} \
|
||||
--openapiv2_opt logtostderr=true \
|
||||
--authoption_out ${GRPC_PATH}/admin \
|
||||
--auth_out ${GOPATH}/src \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
${PROTO_PATH}/admin.proto
|
||||
|
||||
# authoptions are generated into the wrong folder
|
||||
mv ${ZITADEL_PATH}/pkg/grpc/admin/zitadel/* ${ZITADEL_PATH}/pkg/grpc/admin
|
||||
rm -r ${ZITADEL_PATH}/pkg/grpc/admin/zitadel
|
||||
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--grpc-gateway_out ${GOPATH}/src \
|
||||
@ -69,14 +55,10 @@ protoc \
|
||||
--openapiv2_out ${OPENAPI_PATH} \
|
||||
--openapiv2_opt logtostderr=true \
|
||||
--openapiv2_opt allow_delete_body=true \
|
||||
--authoption_out ${GRPC_PATH}/management \
|
||||
--auth_out ${GOPATH}/src \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
${PROTO_PATH}/management.proto
|
||||
|
||||
# authoptions are generated into the wrong folder
|
||||
mv ${ZITADEL_PATH}/pkg/grpc/management/zitadel/* ${ZITADEL_PATH}/pkg/grpc/management
|
||||
rm -r ${ZITADEL_PATH}/pkg/grpc/management/zitadel
|
||||
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--grpc-gateway_out ${GOPATH}/src \
|
||||
@ -85,14 +67,10 @@ protoc \
|
||||
--openapiv2_out ${OPENAPI_PATH} \
|
||||
--openapiv2_opt logtostderr=true \
|
||||
--openapiv2_opt allow_delete_body=true \
|
||||
--authoption_out=${GRPC_PATH}/auth \
|
||||
--auth_out=${GOPATH}/src \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
${PROTO_PATH}/auth.proto
|
||||
|
||||
# authoptions are generated into the wrong folder
|
||||
mv ${ZITADEL_PATH}/pkg/grpc/auth/zitadel/* ${ZITADEL_PATH}/pkg/grpc/auth
|
||||
rm -r ${ZITADEL_PATH}/pkg/grpc/auth/zitadel
|
||||
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--grpc-gateway_out ${GOPATH}/src \
|
||||
@ -101,14 +79,10 @@ protoc \
|
||||
--openapiv2_out ${OPENAPI_PATH} \
|
||||
--openapiv2_opt logtostderr=true \
|
||||
--openapiv2_opt allow_delete_body=true \
|
||||
--authoption_out=${GRPC_PATH}/user \
|
||||
--auth_out=${GOPATH}/src \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
${PROTO_PATH}/user/v2alpha/user_service.proto
|
||||
|
||||
# authoptions are generated into the wrong folder
|
||||
cp -r ${ZITADEL_PATH}/pkg/grpc/user/zitadel/* ${ZITADEL_PATH}/pkg/grpc
|
||||
rm -r ${ZITADEL_PATH}/pkg/grpc/user/zitadel
|
||||
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--grpc-gateway_out ${GOPATH}/src \
|
||||
@ -117,12 +91,8 @@ protoc \
|
||||
--openapiv2_out ${OPENAPI_PATH} \
|
||||
--openapiv2_opt logtostderr=true \
|
||||
--openapiv2_opt allow_delete_body=true \
|
||||
--authoption_out=${GRPC_PATH}/session \
|
||||
--auth_out=${GOPATH}/src \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
${PROTO_PATH}/session/v2alpha/session_service.proto
|
||||
|
||||
# authoptions are generated into the wrong folder
|
||||
cp -r ${ZITADEL_PATH}/pkg/grpc/session/zitadel/* ${ZITADEL_PATH}/pkg/grpc
|
||||
rm -r ${ZITADEL_PATH}/pkg/grpc/session/zitadel
|
||||
|
||||
echo "done generating grpc"
|
||||
|
@ -233,6 +233,8 @@ OIDC:
|
||||
Path: /oidc/v1/end_session
|
||||
Keys:
|
||||
Path: /oauth/v2/keys
|
||||
DeviceAuth:
|
||||
Path: /oauth/v2/device_authorization
|
||||
|
||||
SAML:
|
||||
ProviderConfig:
|
||||
@ -319,6 +321,8 @@ SystemDefaults:
|
||||
ApplicationKeySize: 2048
|
||||
Multifactors:
|
||||
OTP:
|
||||
# If this is empty, the issuer is the requested domain
|
||||
# This is helpful in scenarios with multiple ZITADEL environments or virtual instances
|
||||
Issuer: "ZITADEL"
|
||||
DomainVerification:
|
||||
VerificationGenerator:
|
||||
@ -394,6 +398,7 @@ Quotas:
|
||||
|
||||
Eventstore:
|
||||
PushTimeout: 15s
|
||||
AllowOrderByCreationDate: false
|
||||
|
||||
DefaultInstance:
|
||||
InstanceName:
|
||||
|
@ -76,6 +76,7 @@ func (mig *FirstInstance) Execute(ctx context.Context) error {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
67
cmd/setup/10.go
Normal file
67
cmd/setup/10.go
Normal file
@ -0,0 +1,67 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"time"
|
||||
|
||||
"github.com/cockroachdb/cockroach-go/v2/crdb"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed 10_create_temp_table.sql
|
||||
correctCreationDate10CreateTable string
|
||||
//go:embed 10_fill_table.sql
|
||||
correctCreationDate10FillTable string
|
||||
//go:embed 10_update.sql
|
||||
correctCreationDate10Update string
|
||||
)
|
||||
|
||||
type CorrectCreationDate struct {
|
||||
dbClient *database.DB
|
||||
FailAfter time.Duration
|
||||
}
|
||||
|
||||
func (mig *CorrectCreationDate) Execute(ctx context.Context) (err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, mig.FailAfter)
|
||||
defer cancel()
|
||||
|
||||
for {
|
||||
var affected int64
|
||||
err = crdb.ExecuteTx(ctx, mig.dbClient.DB, nil, func(tx *sql.Tx) error {
|
||||
if mig.dbClient.Type() == "cockroach" {
|
||||
if _, err := tx.Exec("SET experimental_enable_temp_tables=on"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := tx.ExecContext(ctx, correctCreationDate10CreateTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, correctCreationDate10FillTable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := tx.ExecContext(ctx, correctCreationDate10Update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
affected, _ = res.RowsAffected()
|
||||
logging.WithFields("count", affected).Info("creation dates changed")
|
||||
return nil
|
||||
})
|
||||
if affected == 0 || err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mig *CorrectCreationDate) String() string {
|
||||
return "10_correct_creation_date"
|
||||
}
|
6
cmd/setup/10_create_temp_table.sql
Normal file
6
cmd/setup/10_create_temp_table.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE temporary TABLE IF NOT EXISTS wrong_events (
|
||||
instance_id TEXT
|
||||
, event_sequence BIGINT
|
||||
, current_cd TIMESTAMPTZ
|
||||
, next_cd TIMESTAMPTZ
|
||||
);
|
19
cmd/setup/10_fill_table.sql
Normal file
19
cmd/setup/10_fill_table.sql
Normal file
@ -0,0 +1,19 @@
|
||||
TRUNCATE wrong_events;
|
||||
|
||||
INSERT INTO wrong_events (
|
||||
SELECT * FROM (
|
||||
SELECT
|
||||
instance_id
|
||||
, event_sequence
|
||||
, creation_date AS current_cd
|
||||
, lead(creation_date) OVER (
|
||||
PARTITION BY instance_id
|
||||
ORDER BY event_sequence DESC
|
||||
) AS next_cd
|
||||
FROM
|
||||
eventstore.events
|
||||
) sub WHERE
|
||||
current_cd < next_cd
|
||||
ORDER BY
|
||||
event_sequence DESC
|
||||
);
|
1
cmd/setup/10_update.sql
Normal file
1
cmd/setup/10_update.sql
Normal file
@ -0,0 +1 @@
|
||||
UPDATE eventstore.events e SET creation_date = we.next_cd FROM wrong_events we WHERE e.event_sequence = we.event_sequence and e.instance_id = we.instance_id;
|
51
cmd/setup/cleanup.go
Normal file
51
cmd/setup/cleanup.go
Normal file
@ -0,0 +1,51 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/migration"
|
||||
)
|
||||
|
||||
func NewCleanup() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "cleanup",
|
||||
Short: "cleans up migration if they got stuck",
|
||||
Long: `cleans up migration if they got stuck`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
config := MustNewConfig(viper.GetViper())
|
||||
Cleanup(config)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func Cleanup(config *Config) {
|
||||
ctx := context.Background()
|
||||
|
||||
logging.Info("cleanup started")
|
||||
|
||||
dbClient, err := database.Connect(config.Database, false)
|
||||
logging.OnError(err).Fatal("unable to connect to database")
|
||||
|
||||
es, err := eventstore.Start(&eventstore.Config{Client: dbClient})
|
||||
logging.OnError(err).Fatal("unable to start eventstore")
|
||||
migration.RegisterMappers(es)
|
||||
|
||||
step, err := migration.LatestStep(ctx, es)
|
||||
logging.OnError(err).Fatal("unable to query latest migration")
|
||||
|
||||
if step.BaseEvent.EventType != migration.StartedType {
|
||||
logging.Info("there is no stuck migration please run `zitadel setup`")
|
||||
return
|
||||
}
|
||||
|
||||
logging.WithFields("name", step.Name).Info("cleanup migration")
|
||||
|
||||
err = migration.CancelStep(ctx, es, step)
|
||||
logging.OnError(err).Fatal("cleanup migration failed please retry")
|
||||
}
|
@ -65,6 +65,7 @@ type Steps struct {
|
||||
s7LogstoreTables *LogstoreTables
|
||||
s8AuthTokens *AuthTokenIndexes
|
||||
s9EventstoreIndexes2 *EventstoreIndexesNew
|
||||
CorrectCreationDate *CorrectCreationDate
|
||||
}
|
||||
|
||||
type encryptionKeyConfig struct {
|
||||
|
@ -33,7 +33,8 @@ func (mig *externalConfigChange) Check() bool {
|
||||
}
|
||||
|
||||
func (mig *externalConfigChange) Execute(ctx context.Context) error {
|
||||
cmd, err := command.StartCommands(mig.es,
|
||||
cmd, err := command.StartCommands(
|
||||
mig.es,
|
||||
systemdefaults.SystemDefaults{},
|
||||
nil,
|
||||
nil,
|
||||
@ -50,6 +51,7 @@ func (mig *externalConfigChange) Execute(ctx context.Context) error {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
@ -45,6 +45,8 @@ Requirements:
|
||||
},
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewCleanup())
|
||||
|
||||
Flags(cmd)
|
||||
|
||||
return cmd
|
||||
@ -88,6 +90,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
steps.s7LogstoreTables = &LogstoreTables{dbClient: dbClient.DB, username: config.Database.Username(), dbType: config.Database.Type()}
|
||||
steps.s8AuthTokens = &AuthTokenIndexes{dbClient: dbClient}
|
||||
steps.s9EventstoreIndexes2 = New09(dbClient)
|
||||
steps.CorrectCreationDate.dbClient = dbClient
|
||||
|
||||
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil)
|
||||
logging.OnError(err).Fatal("unable to start projections")
|
||||
@ -123,6 +126,8 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
logging.OnError(err).Fatal("unable to migrate step 8")
|
||||
err = migration.Migrate(ctx, eventstoreClient, steps.s9EventstoreIndexes2)
|
||||
logging.OnError(err).Fatal("unable to migrate step 9")
|
||||
err = migration.Migrate(ctx, eventstoreClient, steps.CorrectCreationDate)
|
||||
logging.OnError(err).Fatal("unable to migrate step 10")
|
||||
|
||||
for _, repeatableStep := range repeatableSteps {
|
||||
err = migration.Migrate(ctx, eventstoreClient, repeatableStep)
|
||||
|
@ -30,3 +30,5 @@ FirstInstance:
|
||||
MachineKey:
|
||||
ExpirationDate:
|
||||
Type:
|
||||
CorrectCreationDate:
|
||||
FailAfter: 5m
|
||||
|
@ -12,14 +12,13 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/saml/pkg/provider"
|
||||
|
||||
clockpkg "github.com/benbjohnson/clock"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/oidc/v2/pkg/op"
|
||||
"github.com/zitadel/saml/pkg/provider"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
|
||||
@ -116,7 +115,7 @@ func startZitadel(config *Config, masterKey string) error {
|
||||
return fmt.Errorf("cannot start queries: %w", err)
|
||||
}
|
||||
|
||||
authZRepo, err := authz.Start(queries, dbClient, keys.OIDC, config.ExternalSecure)
|
||||
authZRepo, err := authz.Start(queries, dbClient, keys.OIDC, config.ExternalSecure, config.Eventstore.AllowOrderByCreationDate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting authz repo: %w", err)
|
||||
}
|
||||
@ -147,6 +146,7 @@ func startZitadel(config *Config, masterKey string) error {
|
||||
keys.OIDC,
|
||||
keys.SAML,
|
||||
&http.Client{},
|
||||
authZRepo,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot start commands: %w", err)
|
||||
@ -229,11 +229,11 @@ func startAPIs(
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating api %w", err)
|
||||
}
|
||||
authRepo, err := auth_es.Start(ctx, config.Auth, config.SystemDefaults, commands, queries, dbClient, eventstore, keys.OIDC, keys.User)
|
||||
authRepo, err := auth_es.Start(ctx, config.Auth, config.SystemDefaults, commands, queries, dbClient, eventstore, keys.OIDC, keys.User, config.Eventstore.AllowOrderByCreationDate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting auth repo: %w", err)
|
||||
}
|
||||
adminRepo, err := admin_es.Start(ctx, config.Admin, store, dbClient, eventstore)
|
||||
adminRepo, err := admin_es.Start(ctx, config.Admin, store, dbClient, eventstore, config.Eventstore.AllowOrderByCreationDate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting admin repo: %w", err)
|
||||
}
|
||||
@ -249,7 +249,7 @@ func startAPIs(
|
||||
if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, keys.User, config.ExternalSecure, config.AuditLogRetention)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, user.CreateServer(commands, queries)); err != nil {
|
||||
if err := apis.RegisterService(ctx, user.CreateServer(commands, queries, keys.User)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, session.CreateServer(commands, queries)); err != nil {
|
||||
@ -294,6 +294,7 @@ func startAPIs(
|
||||
return fmt.Errorf("unable to start login: %w", err)
|
||||
}
|
||||
apis.RegisterHandlerOnPrefix(login.HandlerPrefix, l.Handler())
|
||||
apis.HandleFunc(login.EndpointDeviceAuth, login.RedirectDeviceAuthToPrefix)
|
||||
|
||||
// handle grpc at last to be able to handle the root, because grpc and gateway require a lot of different prefixes
|
||||
apis.RouteGRPC()
|
||||
|
@ -1,12 +0,0 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
@ -22,6 +22,7 @@
|
||||
"main": "src/main.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
|
||||
"styles": ["src/styles.scss"],
|
||||
"scripts": ["./node_modules/tinycolor2/dist/tinycolor-min.js"],
|
||||
@ -33,59 +34,24 @@
|
||||
"@angular/common/locales/de",
|
||||
"codemirror/mode/javascript/javascript",
|
||||
"codemirror/mode/xml/xml",
|
||||
"src/app/proto/generated/zitadel/admin_pb",
|
||||
"src/app/proto/generated/zitadel/org_pb",
|
||||
"src/app/proto/generated/zitadel/management_pb",
|
||||
"src/app/proto/generated/zitadel/user_pb",
|
||||
"src/app/proto/generated/**",
|
||||
"google-protobuf/google/protobuf/empty_pb",
|
||||
"file-saver",
|
||||
"qrcode"
|
||||
],
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"buildOptimizer": false,
|
||||
"sourceMap": true,
|
||||
"optimization": {
|
||||
"scripts": true,
|
||||
"fonts": {
|
||||
"inline": true
|
||||
},
|
||||
"styles": {
|
||||
"minify": true,
|
||||
"inlineCritical": false
|
||||
}
|
||||
},
|
||||
"namedChunks": true
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": {
|
||||
"scripts": true,
|
||||
"fonts": {
|
||||
"inline": false
|
||||
},
|
||||
"styles": {
|
||||
"minify": true,
|
||||
"inlineCritical": false
|
||||
}
|
||||
},
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "7mb",
|
||||
"maximumWarning": "6mb",
|
||||
"maximumError": "7mb"
|
||||
},
|
||||
{
|
||||
@ -94,16 +60,21 @@
|
||||
"maximumError": "10kb"
|
||||
}
|
||||
],
|
||||
"serviceWorker": false,
|
||||
"ngswConfigPath": "ngsw-config.json"
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {}
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "console:build:production"
|
||||
@ -123,13 +94,12 @@
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"polyfills": ["zone.js", "zone.js/testing"],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
|
||||
"styles": ["./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css", "src/styles.scss"],
|
||||
"scripts": ["./node_modules/tinycolor2/dist/tinycolor-min.js"]
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["src/styles.scss"],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
@ -137,35 +107,12 @@
|
||||
"options": {
|
||||
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "console:serve:production"
|
||||
},
|
||||
"development": {
|
||||
"devServerTarget": "console:serve:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": "2b4e8e6c-f053-4562-b7a6-00c6c06a6791",
|
||||
"analytics": false,
|
||||
"schematicCollections": ["@angular-eslint/schematics"]
|
||||
},
|
||||
"schematics": {
|
||||
"@angular-eslint/schematics:application": {
|
||||
"setParserOptionsProject": true
|
||||
},
|
||||
"@angular-eslint/schematics:library": {
|
||||
"setParserOptionsProject": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4793
console/package-lock.json
generated
4793
console/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,18 +12,18 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^15.2.2",
|
||||
"@angular/cdk": "^15.2.2",
|
||||
"@angular/common": "^15.2.2",
|
||||
"@angular/compiler": "^15.2.2",
|
||||
"@angular/core": "^15.2.2",
|
||||
"@angular/forms": "^15.2.2",
|
||||
"@angular/material": "^15.2.2",
|
||||
"@angular/material-moment-adapter": "^15.2.2",
|
||||
"@angular/platform-browser": "^15.2.2",
|
||||
"@angular/platform-browser-dynamic": "^15.2.2",
|
||||
"@angular/router": "^15.2.2",
|
||||
"@angular/service-worker": "^15.2.2",
|
||||
"@angular/animations": "^15.2.6",
|
||||
"@angular/cdk": "^15.2.6",
|
||||
"@angular/common": "^15.2.6",
|
||||
"@angular/compiler": "^15.2.6",
|
||||
"@angular/core": "^15.2.6",
|
||||
"@angular/forms": "^15.2.6",
|
||||
"@angular/material": "^15.2.6",
|
||||
"@angular/material-moment-adapter": "^15.2.6",
|
||||
"@angular/platform-browser": "^15.2.6",
|
||||
"@angular/platform-browser-dynamic": "^15.2.6",
|
||||
"@angular/router": "^15.2.6",
|
||||
"@angular/service-worker": "^15.2.6",
|
||||
"@ctrl/ngx-codemirror": "^6.1.0",
|
||||
"@grpc/grpc-js": "^1.8.12",
|
||||
"@ngx-translate/core": "^14.0.0",
|
||||
@ -41,7 +41,7 @@
|
||||
"google-protobuf": "^3.21.2",
|
||||
"grpc-web": "^1.4.1",
|
||||
"i18n-iso-countries": "^7.5.0",
|
||||
"libphonenumber-js": "^1.10.19",
|
||||
"libphonenumber-js": "^1.10.24",
|
||||
"material-design-icons-iconfont": "^6.1.1",
|
||||
"moment": "^2.29.4",
|
||||
"ngx-color": "^8.0.3",
|
||||
@ -49,36 +49,36 @@
|
||||
"tinycolor2": "^1.6.0",
|
||||
"tslib": "^2.4.1",
|
||||
"uuid": "^9.0.0",
|
||||
"zone.js": "~0.12.0"
|
||||
"zone.js": "~0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^15.2.2",
|
||||
"@angular-eslint/builder": "^15.2.1",
|
||||
"@angular-eslint/eslint-plugin": "^15.2.1",
|
||||
"@angular-eslint/eslint-plugin-template": "^15.2.1",
|
||||
"@angular-eslint/schematics": "^15.2.1",
|
||||
"@angular-eslint/template-parser": "^15.2.1",
|
||||
"@angular/cli": "^15.2.2",
|
||||
"@angular/compiler-cli": "^15.2.2",
|
||||
"@angular/language-service": "^15.2.2",
|
||||
"@angular-devkit/build-angular": "^15.2.5",
|
||||
"@angular-eslint/builder": "15.2.1",
|
||||
"@angular-eslint/eslint-plugin": "15.2.1",
|
||||
"@angular-eslint/eslint-plugin-template": "15.2.1",
|
||||
"@angular-eslint/schematics": "15.2.1",
|
||||
"@angular-eslint/template-parser": "15.2.1",
|
||||
"@angular/cli": "^15.2.5",
|
||||
"@angular/compiler-cli": "^15.2.6",
|
||||
"@angular/language-service": "^15.2.6",
|
||||
"@bufbuild/buf": "^1.14.0",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"@types/jasminewd2": "~2.0.10",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/node": "^18.13.0",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.54.1",
|
||||
"@typescript-eslint/parser": "5.54.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.48.2",
|
||||
"@typescript-eslint/parser": "5.48.2",
|
||||
"codelyzer": "^6.0.2",
|
||||
"eslint": "^8.33.0",
|
||||
"jasmine-core": "~4.5.0",
|
||||
"jasmine-core": "~4.6.0",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.4.1",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "^2.0.0",
|
||||
"prettier": "^2.8.4",
|
||||
"prettier": "^2.8.7",
|
||||
"prettier-plugin-organize-imports": "^3.2.2",
|
||||
"protractor": "~7.0.0",
|
||||
"typescript": "^4.9.5"
|
||||
|
@ -201,7 +201,7 @@ export class AppComponent implements OnDestroy {
|
||||
}
|
||||
});
|
||||
|
||||
this.activatedRoute.queryParams.pipe(filter((params) => !!params.org)).subscribe((params) => {
|
||||
this.activatedRoute.queryParams.pipe(filter((params) => !!params['org'])).subscribe((params) => {
|
||||
const { org } = params;
|
||||
this.authService.getActiveOrg(org);
|
||||
});
|
||||
@ -252,7 +252,7 @@ export class AppComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
public prepareRoute(outlet: RouterOutlet): boolean {
|
||||
return outlet && outlet.activatedRouteData && outlet.activatedRouteData.animation;
|
||||
return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
|
||||
}
|
||||
|
||||
public onSetTheme(theme: string): void {
|
||||
@ -267,15 +267,15 @@ export class AppComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
private setLanguage(): void {
|
||||
this.translate.addLangs(['de', 'en', 'fr', 'it', 'ja', 'pl', 'zh']);
|
||||
this.translate.addLangs(['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh']);
|
||||
this.translate.setDefaultLang('en');
|
||||
|
||||
this.authService.user.subscribe((userprofile) => {
|
||||
if (userprofile) {
|
||||
const cropped = navigator.language.split('-')[0] ?? 'en';
|
||||
const fallbackLang = cropped.match(/de|en|fr|it|ja|pl|zh/) ? cropped : 'en';
|
||||
const fallbackLang = cropped.match(/de|en|es|fr|it|ja|pl|zh/) ? cropped : 'en';
|
||||
|
||||
const lang = userprofile?.human?.profile?.preferredLanguage.match(/de|en|fr|it|ja|pl|zh/)
|
||||
const lang = userprofile?.human?.profile?.preferredLanguage.match(/de|en|es|fr|it|ja|pl|zh/)
|
||||
? userprofile.human.profile?.preferredLanguage
|
||||
: fallbackLang;
|
||||
this.translate.use(lang);
|
||||
|
@ -2,6 +2,7 @@ import { CommonModule, registerLocaleData } from '@angular/common';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import localeDe from '@angular/common/locales/de';
|
||||
import localeEn from '@angular/common/locales/en';
|
||||
import localeEs from '@angular/common/locales/es';
|
||||
import localeFr from '@angular/common/locales/fr';
|
||||
import localeIt from '@angular/common/locales/it';
|
||||
import localeJa from '@angular/common/locales/ja';
|
||||
@ -64,6 +65,8 @@ registerLocaleData(localeDe);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/de.json'));
|
||||
registerLocaleData(localeEn);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/en.json'));
|
||||
registerLocaleData(localeEs);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/es.json'));
|
||||
registerLocaleData(localeFr);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/fr.json'));
|
||||
registerLocaleData(localeIt);
|
||||
|
@ -16,7 +16,7 @@ export class UserGuard implements CanActivate {
|
||||
state: RouterStateSnapshot,
|
||||
): Observable<boolean> | Promise<boolean> | boolean {
|
||||
return this.authService.user.pipe(
|
||||
map((user) => user?.id !== route.params.id),
|
||||
map((user) => user?.id !== route.params['id']),
|
||||
tap((isNotMe) => {
|
||||
if (!isNotMe) {
|
||||
this.router.navigate(['/users', 'me']);
|
||||
|
@ -16,9 +16,9 @@
|
||||
<input cnslInput [matDatepicker]="picker" [min]="startDate" [formControl]="dateControl" />
|
||||
<mat-datepicker-toggle style="top: 0" cnslSuffix [for]="picker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker [startAt]="startDate"></mat-datepicker>
|
||||
<span cnslError *ngIf="dateControl?.errors?.matDatepickerMin?.min">
|
||||
<span cnslError *ngIf="dateControl && dateControl.errors && dateControl.errors['matDatepickerMin']?.min">
|
||||
{{ 'USER.MACHINE.CHOOSEDATEAFTER' | translate }}:
|
||||
{{ dateControl.errors?.matDatepickerMin.min.toDate() | localizedDate : 'EEE dd. MMM' }}
|
||||
{{ dateControl.errors['matDatepickerMin'].min.toDate() | localizedDate : 'EEE dd. MMM' }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
@ -7,9 +7,9 @@
|
||||
<input cnslInput [matDatepicker]="picker" [min]="startDate" [formControl]="dateControl" />
|
||||
<mat-datepicker-toggle style="top: 0" cnslSuffix [for]="picker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker startView="year" [startAt]="startDate"></mat-datepicker>
|
||||
<span cnslError *ngIf="dateControl?.errors?.matDatepickerMin?.min">
|
||||
<span cnslError *ngIf="dateControl && dateControl.errors && dateControl.errors['matDatepickerMin']?.min">
|
||||
{{ 'USER.PERSONALACCESSTOKEN.ADD.CHOOSEDATEAFTER' | translate }}:
|
||||
{{ dateControl.errors?.matDatepickerMin.min.toDate() | localizedDate : 'EEE dd. MMM' }}
|
||||
{{ dateControl.errors['matDatepickerMin'].min.toDate() | localizedDate : 'EEE dd. MMM' }}
|
||||
</span>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
@ -16,8 +16,6 @@
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayHasBackdrop]="true"
|
||||
[flexibleDimensions]="true"
|
||||
[lockPosition]="true"
|
||||
[cdkConnectedOverlayOffsetY]="10"
|
||||
[cdkConnectedOverlayPositions]="positions"
|
||||
[cdkConnectedOverlayOrigin]="triggereventfilter"
|
||||
|
@ -24,7 +24,7 @@ export class FilterOrgComponent extends FilterComponent implements OnInit {
|
||||
|
||||
public states: OrgState[] = [OrgState.ORG_STATE_ACTIVE, OrgState.ORG_STATE_INACTIVE, OrgState.ORG_STATE_REMOVED];
|
||||
|
||||
constructor(router: Router, protected route: ActivatedRoute) {
|
||||
constructor(router: Router, protected override route: ActivatedRoute) {
|
||||
super(router, route);
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ export class FilterOrgComponent extends FilterComponent implements OnInit {
|
||||
this.filterChanged.emit(this.searchQueries ? this.searchQueries : []);
|
||||
}
|
||||
|
||||
public emitFilter(): void {
|
||||
public override emitFilter(): void {
|
||||
this.filterChanged.emit(this.searchQueries ? this.searchQueries : []);
|
||||
this.showFilter = false;
|
||||
this.filterOpen.emit(false);
|
||||
|
@ -110,7 +110,7 @@ export class FilterProjectComponent extends FilterComponent implements OnInit {
|
||||
this.filterChanged.emit(this.searchQueries ? this.searchQueries : []);
|
||||
}
|
||||
|
||||
public emitFilter(): void {
|
||||
public override emitFilter(): void {
|
||||
this.filterChanged.emit(this.searchQueries ? this.searchQueries : []);
|
||||
this.showFilter = false;
|
||||
this.filterOpen.emit(false);
|
||||
|
@ -226,7 +226,7 @@ export class FilterUserGrantsComponent extends FilterComponent implements OnInit
|
||||
this.filterChanged.emit(this.searchQueries ? this.searchQueries : []);
|
||||
}
|
||||
|
||||
public emitFilter(): void {
|
||||
public override emitFilter(): void {
|
||||
this.filterChanged.emit(this.searchQueries ? this.searchQueries : []);
|
||||
this.showFilter = false;
|
||||
this.filterOpen.emit(false);
|
||||
|
@ -236,7 +236,7 @@ export class FilterUserComponent extends FilterComponent implements OnInit {
|
||||
this.filterChanged.emit(this.searchQueries ? this.searchQueries : []);
|
||||
}
|
||||
|
||||
public emitFilter(): void {
|
||||
public override emitFilter(): void {
|
||||
this.filterChanged.emit(this.searchQueries ? this.searchQueries : []);
|
||||
this.showFilter = false;
|
||||
this.filterOpen.emit(false);
|
||||
|
@ -15,8 +15,6 @@
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayHasBackdrop]="true"
|
||||
[flexibleDimensions]="true"
|
||||
[lockPosition]="true"
|
||||
[cdkConnectedOverlayOffsetY]="10"
|
||||
[cdkConnectedOverlayPositions]="positions"
|
||||
[cdkConnectedOverlayOrigin]="trigger"
|
||||
|
@ -1,5 +1,14 @@
|
||||
<ng-template #labelTemplate>
|
||||
<label class="cnsl-label-wrapper" [attr.for]="_control.id" [attr.aria-owns]="_control.id">
|
||||
<ng-content select="cnsl-label"></ng-content>
|
||||
<span *ngIf="_control.required && !hideRequiredMarker" aria-hidden="true" class="cnsl-form-field-required-marker"
|
||||
>*</span
|
||||
>
|
||||
</label>
|
||||
</ng-template>
|
||||
|
||||
<div class="cnsl-form-field-wrapper" (click)="_control.onContainerClick && _control.onContainerClick($event)">
|
||||
<ng-content select="cnsl-label"></ng-content>
|
||||
<ng-template [ngTemplateOutlet]="labelTemplate"></ng-template>
|
||||
<div class="cnsl-rel" #inputContainer>
|
||||
<ng-content></ng-content>
|
||||
<ng-content select="cnslSuffix"></ng-content>
|
||||
|
@ -51,6 +51,7 @@ interface ValidationError {
|
||||
'[class.ng-valid]': '_shouldForward("valid")',
|
||||
'[class.ng-invalid]': '_shouldForward("invalid")',
|
||||
'[class.ng-pending]': '_shouldForward("pending")',
|
||||
'[class.ng-required]': '_control.required',
|
||||
'[class.cnsl-form-field-disabled]': '_control.disabled',
|
||||
'[class.cnsl-form-field-autofilled]': '_control.autofilled',
|
||||
'[class.cnsl-focused]': '_control.focused',
|
||||
@ -69,6 +70,7 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr
|
||||
@ContentChild(MatFormFieldControl) _controlNonStatic!: MatFormFieldControl<any>;
|
||||
@ContentChild(MatFormFieldControl, { static: true }) _controlStatic!: MatFormFieldControl<any>;
|
||||
@Input() public disableValidationErrors = false;
|
||||
@Input() public hideRequiredMarker = false;
|
||||
|
||||
get _control(): MatFormFieldControl<any> {
|
||||
return this._explicitFormFieldControl || this._controlNonStatic || this._controlStatic;
|
||||
@ -95,7 +97,7 @@ export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestr
|
||||
}
|
||||
|
||||
constructor(
|
||||
public _elementRef: ElementRef,
|
||||
public override _elementRef: ElementRef,
|
||||
private _changeDetectorRef: ChangeDetectorRef,
|
||||
@Inject(ElementRef)
|
||||
_labelOptions: // Use `ElementRef` here so Angular has something to inject.
|
||||
|
@ -24,6 +24,12 @@ export function requiredValidator(c: AbstractControl): ValidationErrors | null {
|
||||
return i18nErr(Validators.required(c), 'ERRORS.REQUIRED');
|
||||
}
|
||||
|
||||
export function minArrayLengthValidator(minArrLength: number): ValidatorFn {
|
||||
return (c: AbstractControl): ValidationErrors | null => {
|
||||
return arrayLengthValidator(c, minArrLength, 'ERRORS.ATLEASTONE');
|
||||
};
|
||||
}
|
||||
|
||||
export function emailValidator(c: AbstractControl): ValidationErrors | null {
|
||||
return i18nErr(Validators.email(c), 'ERRORS.NOTANEMAIL');
|
||||
}
|
||||
@ -56,6 +62,12 @@ function regexpValidator(c: AbstractControl, regexp: RegExp, i18nKey: string): V
|
||||
return !c.value || regexp.test(c.value) ? null : i18nErr({ invalid: true }, i18nKey, { regexp: regexp });
|
||||
}
|
||||
|
||||
function arrayLengthValidator(c: AbstractControl, length: number, i18nKey: string): ValidationErrors | null {
|
||||
const arr: string[] = c.value;
|
||||
const invalidStrings: string[] = arr.filter((val: string) => val.trim() === '');
|
||||
return arr && invalidStrings.length === 0 && arr.length >= length ? null : i18nErr({ invalid: true }, i18nKey);
|
||||
}
|
||||
|
||||
function i18nErr(err: ValidationErrors | null | undefined, i18nKey: string, params?: any): ValidationErrors | null {
|
||||
if (err === null) {
|
||||
return null;
|
||||
|
@ -110,8 +110,6 @@
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayOrigin]="trigger"
|
||||
[flexibleDimensions]="true"
|
||||
[lockPosition]="true"
|
||||
[cdkConnectedOverlayOffsetY]="10"
|
||||
[cdkConnectedOverlayHasBackdrop]="true"
|
||||
[cdkConnectedOverlayPositions]="positions"
|
||||
@ -221,8 +219,6 @@
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayOrigin]="accounttrigger"
|
||||
[flexibleDimensions]="true"
|
||||
[lockPosition]="true"
|
||||
[cdkConnectedOverlayOffsetY]="10"
|
||||
[cdkConnectedOverlayHasBackdrop]="true"
|
||||
[cdkConnectedOverlayPositions]="accountCardPositions"
|
||||
|
@ -199,7 +199,7 @@ export class InputDirective
|
||||
protected _type: string = 'text';
|
||||
|
||||
/** An object used to control when error messages are shown. */
|
||||
@Input() errorStateMatcher!: ErrorStateMatcher;
|
||||
@Input() override errorStateMatcher!: ErrorStateMatcher;
|
||||
|
||||
/**
|
||||
* Implemented as part of MatFormFieldControl.
|
||||
@ -241,7 +241,7 @@ export class InputDirective
|
||||
protected _elementRef: ElementRef<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
|
||||
protected _platform: Platform,
|
||||
/** @docs-private */
|
||||
@Optional() @Self() public ngControl: NgControl,
|
||||
@Optional() @Self() public override ngControl: NgControl,
|
||||
@Optional() _parentForm: NgForm,
|
||||
@Optional() _parentFormGroup: FormGroupDirective,
|
||||
_defaultErrorStateMatcher: ErrorStateMatcher,
|
||||
|
@ -9,23 +9,31 @@
|
||||
$foreground: map-get($theme, foreground);
|
||||
$secondary-text: map-get($foreground, secondary-text);
|
||||
|
||||
.cnsl-label {
|
||||
display: block;
|
||||
.cnsl-label-wrapper {
|
||||
display: flex;
|
||||
font-size: 12px;
|
||||
color: $secondary-text;
|
||||
transition: color 0.2s ease;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 400;
|
||||
|
||||
.cnsl-label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cnsl-form-field-required-marker {
|
||||
margin-left: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.cnsl-form-field-disabled {
|
||||
.cnsl-label {
|
||||
.cnsl-label-wrapper {
|
||||
color: if($is-dark-theme, #ffffff80, #00000061);
|
||||
}
|
||||
}
|
||||
|
||||
.cnsl-form-field-invalid {
|
||||
.cnsl-label {
|
||||
.cnsl-label-wrapper {
|
||||
color: $warn-color;
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ export class MetadataComponent implements OnChanges {
|
||||
constructor() {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.metadata?.currentValue) {
|
||||
this.dataSource = new MatTableDataSource<Metadata.AsObject>(changes.metadata.currentValue);
|
||||
if (changes['metadata']?.currentValue) {
|
||||
this.dataSource = new MatTableDataSource<Metadata.AsObject>(changes['metadata'].currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@
|
||||
<span class="label">{{ 'MENU.DASHBOARD' | translate }}</span>
|
||||
</a>
|
||||
|
||||
<ng-container class="org-list" *ngIf="org" [@navAnimation]="org">
|
||||
<ng-container class="org-list" *ngIf="org">
|
||||
<ng-template cnslHasRole [hasRole]="['org.read']">
|
||||
<a
|
||||
class="nav-item"
|
||||
@ -232,8 +232,6 @@
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayOrigin]="trigger"
|
||||
[flexibleDimensions]="true"
|
||||
[lockPosition]="true"
|
||||
[cdkConnectedOverlayOffsetY]="10"
|
||||
[cdkConnectedOverlayHasBackdrop]="true"
|
||||
[cdkConnectedOverlayPositions]="positions"
|
||||
|
@ -198,6 +198,12 @@
|
||||
.state-circle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.action-card {
|
||||
.action-content {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
<ng-template #showSpinner>
|
||||
<div
|
||||
*ngIf="password?.errors?.minlength || password?.value?.length === 0 as currentError; else trueminlength"
|
||||
*ngIf="
|
||||
(password && password.errors && password.errors['minlength']) || password?.value?.length === 0 as currentError;
|
||||
else trueminlength
|
||||
"
|
||||
class="complexity-sp-wrapper"
|
||||
>
|
||||
<mat-progress-spinner
|
||||
@ -28,23 +31,23 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="val" *ngIf="this.policy.hasSymbol">
|
||||
<i *ngIf="password?.pristine || password?.errors?.errorssymbolerror" class="las la-times red"></i>
|
||||
<i *ngIf="password?.dirty && !password?.errors?.errorssymbolerror" class="las la-check green"></i>
|
||||
<i *ngIf="password?.pristine || password?.errors?.['errorssymbolerror']" class="las la-times red"></i>
|
||||
<i *ngIf="password?.dirty && !password?.errors?.['errorssymbolerror']" class="las la-check green"></i>
|
||||
<span class="cnsl-secondary-text"> {{ 'ERRORS.SYMBOLERROR' | translate }}</span>
|
||||
</div>
|
||||
<div class="val" *ngIf="this.policy.hasNumber">
|
||||
<i *ngIf="password?.pristine || password?.errors?.errorsnumbererror" class="las la-times red"></i>
|
||||
<i *ngIf="password?.dirty && !password?.errors?.errorsnumbererror" class="las la-check green"></i>
|
||||
<i *ngIf="password?.pristine || password?.errors?.['errorsnumbererror']" class="las la-times red"></i>
|
||||
<i *ngIf="password?.dirty && !password?.errors?.['errorsnumbererror']" class="las la-check green"></i>
|
||||
<span class="cnsl-secondary-text"> {{ 'ERRORS.NUMBERERROR' | translate }}</span>
|
||||
</div>
|
||||
<div class="val" *ngIf="this.policy.hasUppercase">
|
||||
<i *ngIf="password?.pristine || password?.errors?.errorsuppercasemissing" class="las la-times red"></i>
|
||||
<i *ngIf="password?.dirty && !password?.errors?.errorsuppercasemissing" class="las la-check green"></i>
|
||||
<i *ngIf="password?.pristine || password?.errors?.['errorsuppercasemissing']" class="las la-times red"></i>
|
||||
<i *ngIf="password?.dirty && !password?.errors?.['errorsuppercasemissing']" class="las la-check green"></i>
|
||||
<span class="cnsl-secondary-text"> {{ 'ERRORS.UPPERCASEMISSING' | translate }}</span>
|
||||
</div>
|
||||
<div class="val" *ngIf="this.policy.hasLowercase">
|
||||
<i *ngIf="password?.pristine || password?.errors?.errorslowercasemissing" class="las la-times red"></i>
|
||||
<i *ngIf="password?.dirty && !password?.errors?.errorslowercasemissing" class="las la-check green"></i>
|
||||
<i *ngIf="password?.pristine || password?.errors?.['errorslowercasemissing']" class="las la-times red"></i>
|
||||
<i *ngIf="password?.dirty && !password?.errors?.['errorslowercasemissing']" class="las la-check green"></i>
|
||||
<span class="cnsl-secondary-text">{{ 'ERRORS.LOWERCASEMISSING' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -109,7 +109,7 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
@Input() public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
|
||||
public KeyNamesArray: string[] = KeyNamesArray;
|
||||
public LOCALES: string[] = ['de', 'en', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
public LOCALES: string[] = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
|
||||
private sub: Subscription = new Subscription();
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
||||
<div class="message-text-actions">
|
||||
<button
|
||||
class="reset-button"
|
||||
*ngIf="(getCustomInitMessageTextMap$ | async) && (getCustomInitMessageTextMap$ | async)?.isDefault === false"
|
||||
*ngIf="(getCustomInitMessageTextMap$ | async) && (getCustomInitMessageTextMap$ | async)?.['isDefault'] === false"
|
||||
[disabled]="(canWrite$ | async) === false"
|
||||
(click)="resetDefault()"
|
||||
color="message-text-warn"
|
||||
|
@ -441,7 +441,7 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
|
||||
public locale: string = 'en';
|
||||
public LOCALES: string[] = ['de', 'en', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
public LOCALES: string[] = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
private sub: Subscription = new Subscription();
|
||||
public canWrite$: Observable<boolean> = this.authService.isAllowed([
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
|
@ -45,13 +45,13 @@ export class ProjectMembersComponent {
|
||||
private route: ActivatedRoute,
|
||||
) {
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.projectType = data.type;
|
||||
this.projectType = data['type'];
|
||||
|
||||
this.getRoleOptions();
|
||||
|
||||
this.route.params.subscribe((params) => {
|
||||
this.projectId = params.projectid;
|
||||
this.grantId = params.grantid;
|
||||
this.projectId = params['projectid'];
|
||||
this.grantId = params['grantid'];
|
||||
this.loadMembers();
|
||||
});
|
||||
});
|
||||
|
@ -1,54 +1,65 @@
|
||||
<form [formGroup]="form" class="attribute-form">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.LDAPIDATTRIBUTE' | translate }}*</cnsl-label>
|
||||
<input cnslInput formControlName="idAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.AVATARURLATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="avatarUrlAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.DISPLAYNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="displayNameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.EMAILATTRIBUTEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="emailAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.EMAILVERIFIEDATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="emailVerifiedAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.FIRSTNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="firstNameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.LASTNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="lastNameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NICKNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="nickNameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PHONEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="phoneAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PHONEVERIFIEDATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="phoneVerifiedAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PREFERREDLANGUAGEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="preferredLanguageAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PREFERREDUSERNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="preferredUsernameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PROFILEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="profileAttribute" />
|
||||
<cnsl-label>{{ 'IDP.LDAPIDATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="idAttribute" required />
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="attribute-more-row">
|
||||
<span>{{ 'ACTIONS.MORE' | translate }}</span>
|
||||
<button (click)="showMore = !showMore" type="button" mat-icon-button>
|
||||
<mat-icon *ngIf="showMore">keyboard_arrow_up</mat-icon>
|
||||
<mat-icon *ngIf="!showMore">keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="showMore">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.AVATARURLATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="avatarUrlAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.DISPLAYNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="displayNameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.EMAILATTRIBUTEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="emailAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.EMAILVERIFIEDATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="emailVerifiedAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.FIRSTNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="firstNameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.LASTNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="lastNameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NICKNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="nickNameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PHONEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="phoneAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PHONEVERIFIEDATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="phoneVerifiedAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PREFERREDLANGUAGEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="preferredLanguageAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PREFERREDUSERNAMEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="preferredUsernameAttribute" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.PROFILEATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="profileAttribute" />
|
||||
</cnsl-form-field>
|
||||
</ng-container>
|
||||
</form>
|
||||
|
@ -4,3 +4,8 @@
|
||||
max-width: 400px;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.attribute-more-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ export class LDAPAttributesComponent implements OnChanges, OnDestroy {
|
||||
profileAttribute: new FormControl('', []),
|
||||
});
|
||||
|
||||
public showMore: boolean = false;
|
||||
constructor() {
|
||||
this.form.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
||||
if (value) {
|
||||
|
@ -25,9 +25,14 @@
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<mat-checkbox
|
||||
class="update-secret-checkbox"
|
||||
*ngIf="provider"
|
||||
[(ngModel)]="updateClientSecret"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>{{ 'IDP.UPDATECLIENTSECRET' | translate }}</mat-checkbox
|
||||
>
|
||||
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
@ -85,7 +90,7 @@
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-form-field class="formfield" *ngIf="tenantType?.value === AzureTenantIDType">
|
||||
<cnsl-label>{{ 'IDP.AZUREADTENANTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="tenantId" />
|
||||
</cnsl-form-field>
|
||||
|
@ -44,7 +44,10 @@ export class ProviderAzureADComponent {
|
||||
|
||||
public provider?: Provider.AsObject;
|
||||
public updateClientSecret: boolean = false;
|
||||
|
||||
public AzureTenantIDType: number = 3;
|
||||
public tenantTypes = [
|
||||
this.AzureTenantIDType,
|
||||
AzureADTenantType.AZURE_AD_TENANT_TYPE_COMMON,
|
||||
AzureADTenantType.AZURE_AD_TENANT_TYPE_ORGANISATIONS,
|
||||
AzureADTenantType.AZURE_AD_TENANT_TYPE_CONSUMERS,
|
||||
@ -86,7 +89,7 @@ export class ProviderAzureADComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
@ -126,15 +129,34 @@ export class ProviderAzureADComponent {
|
||||
: new MgmtGetProviderByIDRequest();
|
||||
req.setId(id);
|
||||
this.service
|
||||
.getProviderByID(req)
|
||||
.getProviderID(req)
|
||||
.then((resp) => {
|
||||
this.provider = resp.idp;
|
||||
const object = resp.toObject();
|
||||
this.provider = object.idp;
|
||||
this.loading = false;
|
||||
if (this.provider?.config?.azureAd) {
|
||||
this.form.patchValue(this.provider.config.azureAd);
|
||||
this.name?.setValue(this.provider.name);
|
||||
this.tenantId?.setValue(this.provider.config.azureAd.tenant?.tenantId);
|
||||
this.tenantType?.setValue(this.provider.config.azureAd.tenant?.tenantType);
|
||||
|
||||
const tenant = resp.getIdp()?.getConfig()?.getAzureAd()?.getTenant();
|
||||
|
||||
if (tenant) {
|
||||
switch (tenant.getTypeCase()) {
|
||||
case AzureADTenant.TypeCase.TENANT_ID:
|
||||
this.tenantId?.setValue(tenant.getTenantId());
|
||||
this.tenantType?.setValue(this.AzureTenantIDType);
|
||||
break;
|
||||
case AzureADTenant.TypeCase.TENANT_TYPE:
|
||||
this.tenantType?.setValue(tenant.getTenantType());
|
||||
this.tenantId?.setValue('');
|
||||
break;
|
||||
case AzureADTenant.TypeCase.TYPE_NOT_SET:
|
||||
this.tenantType?.setValue(this.AzureTenantIDType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -159,8 +181,11 @@ export class ProviderAzureADComponent {
|
||||
req.setEmailVerified(this.emailVerified?.value);
|
||||
|
||||
const tenant = new AzureADTenant();
|
||||
tenant.setTenantId(this.tenantId?.value);
|
||||
tenant.setTenantType(this.tenantType?.value);
|
||||
if (this.tenantType?.value === this.AzureTenantIDType) {
|
||||
tenant.setTenantId(this.tenantId?.value);
|
||||
} else {
|
||||
tenant.setTenantType(this.tenantType?.value);
|
||||
}
|
||||
req.setTenant(tenant);
|
||||
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
@ -194,9 +219,11 @@ export class ProviderAzureADComponent {
|
||||
req.setEmailVerified(this.emailVerified?.value);
|
||||
|
||||
const tenant = new AzureADTenant();
|
||||
|
||||
tenant.setTenantId(this.tenantId?.value);
|
||||
tenant.setTenantType(this.tenantType?.value);
|
||||
if (this.tenantType?.value === this.AzureTenantIDType) {
|
||||
tenant.setTenantId(this.tenantId?.value);
|
||||
} else {
|
||||
tenant.setTenantType(this.tenantType?.value);
|
||||
}
|
||||
req.setTenant(tenant);
|
||||
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
@ -40,9 +40,14 @@
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<mat-checkbox
|
||||
class="update-secret-checkbox"
|
||||
*ngIf="provider"
|
||||
[(ngModel)]="updateClientSecret"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>{{ 'IDP.UPDATECLIENTSECRET' | translate }}</mat-checkbox
|
||||
>
|
||||
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
|
@ -80,7 +80,7 @@ export class ProviderGithubESComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
@ -153,6 +153,7 @@ export class ProviderGithubESComponent {
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
this.service
|
||||
@ -183,6 +184,7 @@ export class ProviderGithubESComponent {
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
this.service
|
||||
|
@ -21,9 +21,14 @@
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<mat-checkbox
|
||||
class="update-secret-checkbox"
|
||||
*ngIf="provider"
|
||||
[(ngModel)]="updateClientSecret"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>{{ 'IDP.UPDATECLIENTSECRET' | translate }}</mat-checkbox
|
||||
>
|
||||
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
|
@ -78,7 +78,7 @@ export class ProviderGithubComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
|
@ -30,9 +30,14 @@
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<mat-checkbox
|
||||
class="update-secret-checkbox"
|
||||
*ngIf="provider"
|
||||
[(ngModel)]="updateClientSecret"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>{{ 'IDP.UPDATECLIENTSECRET' | translate }}</mat-checkbox
|
||||
>
|
||||
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
|
@ -79,7 +79,7 @@ export class ProviderGitlabSelfHostedComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
|
@ -20,9 +20,14 @@
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<mat-checkbox
|
||||
class="update-secret-checkbox"
|
||||
*ngIf="provider"
|
||||
[(ngModel)]="updateClientSecret"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>{{ 'IDP.UPDATECLIENTSECRET' | translate }}</mat-checkbox
|
||||
>
|
||||
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
|
@ -78,7 +78,7 @@ export class ProviderGitlabComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
|
@ -20,9 +20,13 @@
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<mat-checkbox
|
||||
class="update-secret-checkbox"
|
||||
*ngIf="provider"
|
||||
[(ngModel)]="updateClientSecret"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>{{ 'IDP.UPDATECLIENTSECRET' | translate }}</mat-checkbox
|
||||
>
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
|
@ -78,7 +78,7 @@ export class ProviderGoogleComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
|
@ -51,7 +51,7 @@ export class ProviderJWTComponent {
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
|
@ -17,12 +17,13 @@
|
||||
<div class="identity-provider-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
<input cnslInput formControlName="name" required />
|
||||
</cnsl-form-field>
|
||||
|
||||
<h2 class="subheader">{{ 'IDP.LDAPCONNECTION' | translate }}</h2>
|
||||
|
||||
<cnsl-string-list
|
||||
class="string-list-component-wrapper"
|
||||
title="{{ 'IDP.SERVERS' | translate }}"
|
||||
formControlName="serversList"
|
||||
[required]="true"
|
||||
@ -30,21 +31,31 @@
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.BASEDN' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="baseDn" />
|
||||
<input cnslInput formControlName="baseDn" required />
|
||||
</cnsl-form-field>
|
||||
|
||||
<div [ngClass]="{ 'identity-provider-2-col': !provider }">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.BINDDN' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="bindDn" />
|
||||
<input cnslInput formControlName="bindDn" required />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateBindPassword" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATEBINDPASSWORD' | translate
|
||||
}}</mat-checkbox>
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateBindPassword)" class="formfield">
|
||||
<mat-checkbox
|
||||
class="update-secret-checkbox"
|
||||
*ngIf="provider"
|
||||
[(ngModel)]="updateBindPassword"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>{{ 'IDP.UPDATEBINDPASSWORD' | translate }}</mat-checkbox
|
||||
>
|
||||
<cnsl-form-field class="formfield pwd" [ngClass]="{ show: !provider || (provider && updateBindPassword) }">
|
||||
<cnsl-label>{{ 'IDP.BINDPASSWORD' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="bindPassword" />
|
||||
<input
|
||||
cnslInput
|
||||
formControlName="bindPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
[required]="!provider"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
@ -52,16 +63,18 @@
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.USERBASE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="userBase" />
|
||||
<input cnslInput formControlName="userBase" required />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-string-list
|
||||
class="string-list-component-wrapper"
|
||||
title="{{ 'IDP.USERFILTERS' | translate }}"
|
||||
formControlName="userFiltersList"
|
||||
[required]="true"
|
||||
></cnsl-string-list>
|
||||
|
||||
<cnsl-string-list
|
||||
class="string-list-component-wrapper"
|
||||
title="{{ 'IDP.USEROBJECTCLASSES' | translate }}"
|
||||
formControlName="userObjectClassesList"
|
||||
[required]="true"
|
||||
@ -69,22 +82,11 @@
|
||||
|
||||
<div class="identity-provider-optional-h-wrapper">
|
||||
<h2>{{ 'IDP.LDAPATTRIBUTES' | translate }}</h2>
|
||||
|
||||
<button (click)="showAttributes = !showAttributes" type="button" mat-icon-button>
|
||||
<mat-icon *ngIf="showAttributes">keyboard_arrow_up</mat-icon>
|
||||
<mat-icon *ngIf="!showAttributes">keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
|
||||
<span *ngIf="!provider?.config?.ldap?.attributes?.idAttribute" class="state error">{{
|
||||
'IDP.REQUIRED' | translate
|
||||
}}</span>
|
||||
</div>
|
||||
<div *ngIf="showAttributes">
|
||||
<cnsl-ldap-attributes
|
||||
[initialAttributes]="provider?.config?.ldap?.attributes"
|
||||
(attributesChanged)="attributes = $event"
|
||||
></cnsl-ldap-attributes>
|
||||
</div>
|
||||
<cnsl-ldap-attributes
|
||||
[initialAttributes]="provider?.config?.ldap?.attributes"
|
||||
(attributesChanged)="attributes = $event"
|
||||
></cnsl-ldap-attributes>
|
||||
|
||||
<div class="identity-provider-optional-h-wrapper">
|
||||
<h2>{{ 'IDP.OPTIONAL' | translate }}</h2>
|
||||
@ -113,7 +115,7 @@
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="(form.invalid && attributes.toObject().idAttribute !== '') || form.disabled"
|
||||
[disabled]="!form.valid || !attributes.toObject().idAttribute || form.disabled"
|
||||
type="submit"
|
||||
>
|
||||
<span *ngIf="id">{{ 'ACTIONS.SAVE' | translate }}</span>
|
||||
|
@ -20,7 +20,7 @@ import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { requiredValidator } from '../../form-field/validators/validators';
|
||||
import { minArrayLengthValidator, requiredValidator } from '../../form-field/validators/validators';
|
||||
|
||||
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
|
||||
|
||||
@ -30,7 +30,6 @@ import { PolicyComponentServiceType } from '../../policies/policy-component-type
|
||||
})
|
||||
export class ProviderLDAPComponent {
|
||||
public updateBindPassword: boolean = false;
|
||||
public showAttributes: boolean = false;
|
||||
public showOptional: boolean = false;
|
||||
public options: Options = new Options().setIsCreationAllowed(true).setIsLinkingAllowed(true);
|
||||
public attributes: LDAPAttributes = new LDAPAttributes();
|
||||
@ -54,15 +53,15 @@ export class ProviderLDAPComponent {
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
name: new FormControl('', [requiredValidator]),
|
||||
serversList: new FormControl('', [requiredValidator]),
|
||||
serversList: new FormControl<string[]>([''], [minArrayLengthValidator(1)]),
|
||||
baseDn: new FormControl('', [requiredValidator]),
|
||||
bindDn: new FormControl('', [requiredValidator]),
|
||||
bindPassword: new FormControl('', [requiredValidator]),
|
||||
userBase: new FormControl('', [requiredValidator]),
|
||||
userFiltersList: new FormControl('', [requiredValidator]),
|
||||
userObjectClassesList: new FormControl('', [requiredValidator]),
|
||||
userFiltersList: new FormControl<string[]>([''], [minArrayLengthValidator(1)]),
|
||||
userObjectClassesList: new FormControl<string[]>([''], [minArrayLengthValidator(1)]),
|
||||
timeout: new FormControl<number>(0),
|
||||
startTls: new FormControl(false),
|
||||
startTls: new FormControl<boolean>(false),
|
||||
});
|
||||
|
||||
this.authService
|
||||
@ -83,7 +82,7 @@ export class ProviderLDAPComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
@ -112,6 +111,7 @@ export class ProviderLDAPComponent {
|
||||
if (this.id) {
|
||||
this.getData(this.id);
|
||||
this.bindPassword?.setValidators([]);
|
||||
this.bindPassword?.updateValueAndValidity();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -125,12 +125,25 @@ export class ProviderLDAPComponent {
|
||||
this.service
|
||||
.getProviderByID(req)
|
||||
.then((resp) => {
|
||||
this.provider = resp.idp;
|
||||
this.loading = false;
|
||||
if (this.provider?.config?.ldap) {
|
||||
this.form.patchValue(this.provider.config.ldap);
|
||||
if (resp.idp) {
|
||||
this.provider = resp.idp;
|
||||
this.loading = false;
|
||||
|
||||
this.name?.setValue(this.provider.name);
|
||||
this.timeout?.setValue(this.provider.config.ldap.timeout?.seconds);
|
||||
|
||||
const config = this.provider?.config?.ldap;
|
||||
if (config) {
|
||||
this.serversList?.setValue(config.serversList);
|
||||
this.startTls?.setValue(config.startTls);
|
||||
this.baseDn?.setValue(config.baseDn);
|
||||
this.bindDn?.setValue(config.bindDn);
|
||||
this.userBase?.setValue(config.userBase);
|
||||
this.userObjectClassesList?.setValue(config.userObjectClassesList);
|
||||
this.userFiltersList?.setValue(config.userFiltersList);
|
||||
if (this.provider?.config?.ldap?.timeout?.seconds) {
|
||||
this.timeout?.setValue(this.provider?.config?.ldap?.timeout?.seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -13,40 +13,45 @@
|
||||
<p class="identity-provider-desc cnsl-secondary-text">{{ 'IDP.CREATE.OAUTH.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="submitForm()">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.AUTHORIZATIONENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="authorizationEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.TOKENENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="tokenEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.USERENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="userEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.IDATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="idAttribute" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="identity-provider-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.AUTHORIZATIONENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="authorizationEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.TOKENENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="tokenEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.USERENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="userEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.IDATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="idAttribute" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<mat-checkbox
|
||||
class="update-secret-checkbox"
|
||||
*ngIf="provider"
|
||||
[(ngModel)]="updateClientSecret"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>{{ 'IDP.UPDATECLIENTSECRET' | translate }}</mat-checkbox
|
||||
>
|
||||
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
|
@ -81,7 +81,7 @@ export class ProviderOAuthComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
@ -155,6 +155,7 @@ export class ProviderOAuthComponent {
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
this.service
|
||||
@ -186,6 +187,7 @@ export class ProviderOAuthComponent {
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
this.service
|
||||
|
@ -59,7 +59,7 @@ export class ProviderOIDCComponent {
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
this.serviceType = data['serviceType'];
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
@ -130,6 +130,7 @@ export class ProviderOIDCComponent {
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
this.service
|
||||
@ -158,6 +159,7 @@ export class ProviderOIDCComponent {
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
this.service
|
||||
|
@ -1,5 +1,8 @@
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
@mixin identity-provider-theme($theme) {
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$background: map-get($theme, background);
|
||||
|
||||
.identity-provider-desc {
|
||||
font-size: 14px;
|
||||
@ -36,10 +39,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
.update-secret-checkbox {
|
||||
margin: 0.5rem 0 0 0;
|
||||
}
|
||||
|
||||
.formfield {
|
||||
display: block;
|
||||
max-width: 400px;
|
||||
|
||||
&.pwd {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.pwd.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.name-hint {
|
||||
font-size: 12px;
|
||||
}
|
||||
@ -59,6 +74,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.string-list-component-wrapper {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.identity-provider-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -19,10 +19,10 @@ export class SettingsListComponent implements OnChanges {
|
||||
constructor() {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.selectedId?.currentValue) {
|
||||
if (changes['selectedId']?.currentValue) {
|
||||
this.currentSetting =
|
||||
this.settingsList && this.settingsList.find((l) => l.id === changes.selectedId.currentValue)
|
||||
? changes.selectedId.currentValue
|
||||
this.settingsList && this.settingsList.find((l) => l.id === changes['selectedId'].currentValue)
|
||||
? changes['selectedId'].currentValue
|
||||
: '';
|
||||
} else {
|
||||
this.currentSetting = this.settingsList ? this.settingsList[0].id : '';
|
||||
|
@ -1,30 +1,43 @@
|
||||
<form class="string-list-form" (ngSubmit)="add(redInput)">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ title }}</cnsl-label>
|
||||
<input #redInput cnslInput [formControl]="control" />
|
||||
</cnsl-form-field>
|
||||
<button
|
||||
matTooltip="{{ 'ACTIONS.ADD' | translate }}"
|
||||
type="submit"
|
||||
mat-icon-button
|
||||
[disabled]="control.invalid || control.disabled"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</form>
|
||||
<div class="form-array-list">
|
||||
<div class="form-field-list">
|
||||
<div class="list-header-wrapper">
|
||||
<p class="list-header cnsl-secondary-text">{{ title }}*</p>
|
||||
<button
|
||||
class="add-element-btn"
|
||||
matTooltip="{{ 'ACTIONS.ADD' | translate }}"
|
||||
type="button"
|
||||
mat-icon-button
|
||||
(click)="addArrayEntry()"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<ng-container *ngFor="let formControl of formArray.controls; index as i">
|
||||
<div class="element-row">
|
||||
<cnsl-form-field class="formfield" [hideRequiredMarker]="true">
|
||||
<input cnslInput title="{{ 'IDP.SERVERS' | translate }}" [formControl]="$any(formControl)" required />
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="string-list">
|
||||
<div *ngFor="let str of value" class="value-line">
|
||||
<span>{{ str }}</span>
|
||||
<span class="fill-space"></span>
|
||||
<button
|
||||
type="button"
|
||||
matTooltip="{{ 'ACTIONS.DELETE' | translate }}"
|
||||
mat-icon-button
|
||||
(click)="remove(str)"
|
||||
class="icon-button"
|
||||
>
|
||||
<mat-icon class="icon">cancel</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
class="add-element-btn"
|
||||
[disabled]="i === 0 && formArray.controls.length === 1 && formControl.value === ''"
|
||||
[matTooltip]="
|
||||
i === 0 && formArray.controls.length === 1 ? ('ACTIONS.CLEAR' | translate) : ('ACTIONS.REMOVE' | translate)
|
||||
"
|
||||
type="button"
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
(click)="i === 0 && formArray.controls.length === 1 ? clearEntryAtIndex(i) : removeEntryAtIndex(i)"
|
||||
>
|
||||
<i *ngIf="i === 0 && formArray.controls.length === 1; else removeIcon" class="las la-times-circle"></i>
|
||||
<ng-template #removeIcon>
|
||||
<i class="las la-minus-circle"></i>
|
||||
</ng-template>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
<span class="control-error" *ngIf="control.touched && control.errors && control.errors['errorsatleastone']">{{
|
||||
control.errors['errorsatleastone'].i18nKey | translate
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,56 +5,50 @@
|
||||
$background: map-get($theme, background);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$warn: map-get($theme, warn);
|
||||
$warn-color: map-get($warn, 500);
|
||||
$button-text-color: map-get($foreground, text);
|
||||
$button-disabled-text-color: map-get($foreground, disabled-button);
|
||||
$divider-color: map-get($foreground, dividers);
|
||||
$secondary-text: map-get($foreground, secondary-text);
|
||||
$warncolor: map-get($warn, 500);
|
||||
|
||||
.string-list {
|
||||
width: 100%;
|
||||
.form-array-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
max-width: 400px;
|
||||
background: if($is-dark-theme, #00000020, mat.get-color-from-palette($background, cards));
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
padding: 0 1rem 0.5rem 1rem;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
.value-line {
|
||||
.list-header-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0.5rem 0;
|
||||
padding: 0 0 0 0.75rem;
|
||||
border-radius: 4px;
|
||||
background: map-get($background, infosection);
|
||||
margin: 0.5rem -0.5rem 0 0;
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
.list-header {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
.form-field-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.icon {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.element-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:not(:hover) {
|
||||
color: $secondary-text;
|
||||
.formfield {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.control-error {
|
||||
font-size: 12px;
|
||||
color: $warncolor;
|
||||
}
|
||||
}
|
||||
|
||||
.add-element-btn {
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.string-list-form {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
min-width: 320px;
|
||||
|
||||
.formfield {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-bottom: 0.9rem;
|
||||
margin-right: -0.5rem;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component, forwardRef, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { Observable, Subject, takeUntil } from 'rxjs';
|
||||
import { requiredValidator } from '../form-field/validators/validators';
|
||||
import { Component, forwardRef, Input, OnDestroy, ViewChildren, ViewEncapsulation } from '@angular/core';
|
||||
import { ControlValueAccessor, FormArray, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { distinctUntilChanged, Subject, takeUntil } from 'rxjs';
|
||||
import { minArrayLengthValidator, requiredValidator } from '../form-field/validators/validators';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-string-list',
|
||||
@ -16,22 +16,23 @@ import { requiredValidator } from '../form-field/validators/validators';
|
||||
},
|
||||
],
|
||||
})
|
||||
export class StringListComponent implements ControlValueAccessor, OnInit, OnDestroy {
|
||||
export class StringListComponent implements ControlValueAccessor, OnDestroy {
|
||||
@Input() title: string = '';
|
||||
@Input() required: boolean = false;
|
||||
@Input() public getValues: Observable<void> = new Observable(); // adds formfieldinput to array on emission
|
||||
|
||||
@Input() public control: FormControl = new FormControl<string>({ value: '', disabled: true });
|
||||
@Input() public control: FormControl = new FormControl<string[]>({ value: [], disabled: true });
|
||||
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
@ViewChild('redInput') input!: any;
|
||||
private val: string[] = [];
|
||||
@ViewChildren('stringInput') input!: any[];
|
||||
public val: string[] = [];
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getValues.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
||||
this.add(this.input.nativeElement);
|
||||
public formArray: FormArray = new FormArray([new FormControl('', [requiredValidator])]);
|
||||
|
||||
constructor() {
|
||||
this.control.setValidators([minArrayLengthValidator(1)]);
|
||||
this.formArray.valueChanges.pipe(takeUntil(this.destroy$), distinctUntilChanged()).subscribe((value) => {
|
||||
this.value = value;
|
||||
});
|
||||
|
||||
this.required ? this.control.setValidators([requiredValidator]) : this.control.setValidators([]);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@ -50,12 +51,24 @@ export class StringListComponent implements ControlValueAccessor, OnInit, OnDest
|
||||
}
|
||||
}
|
||||
|
||||
addArrayEntry() {
|
||||
this.formArray.push(new FormControl('', [requiredValidator]));
|
||||
}
|
||||
|
||||
removeEntryAtIndex(index: number) {
|
||||
this.formArray.removeAt(index);
|
||||
}
|
||||
|
||||
clearEntryAtIndex(index: number) {
|
||||
this.formArray.controls[index].setValue('');
|
||||
}
|
||||
get value() {
|
||||
return this.val;
|
||||
}
|
||||
|
||||
writeValue(value: string[]) {
|
||||
this.value = value;
|
||||
value.map((v, i) => this.formArray.setControl(i, new FormControl(v, [requiredValidator])));
|
||||
}
|
||||
|
||||
registerOnChange(fn: any) {
|
||||
@ -73,28 +86,4 @@ export class StringListComponent implements ControlValueAccessor, OnInit, OnDest
|
||||
this.control.enable();
|
||||
}
|
||||
}
|
||||
|
||||
public add(input: any): void {
|
||||
if (this.control.valid) {
|
||||
const trimmed = input.value.trim();
|
||||
if (trimmed) {
|
||||
this.val ? this.val.push(input.value) : (this.val = [input.value]);
|
||||
this.onChange(this.val);
|
||||
this.onTouch(this.val);
|
||||
}
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public remove(str: string): void {
|
||||
const index = this.value.indexOf(str);
|
||||
|
||||
if (index >= 0) {
|
||||
this.value.splice(index, 1);
|
||||
this.onChange(this.value);
|
||||
this.onTouch(this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatLegacyButtonModule } from '@angular/material/legacy-button';
|
||||
import { MatLegacyChipsModule } from '@angular/material/legacy-chips';
|
||||
import { MatLegacyTooltipModule } from '@angular/material/legacy-tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from '../input/input.module';
|
||||
@ -15,6 +16,7 @@ import { StringListComponent } from './string-list.component';
|
||||
InputModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatLegacyChipsModule,
|
||||
TranslateModule,
|
||||
MatIconModule,
|
||||
MatLegacyTooltipModule,
|
||||
|
@ -45,7 +45,7 @@ export class OrgCreateComponent {
|
||||
public pwdForm?: UntypedFormGroup;
|
||||
|
||||
public genders: Gender[] = [Gender.GENDER_FEMALE, Gender.GENDER_MALE, Gender.GENDER_UNSPECIFIED];
|
||||
public languages: string[] = ['de', 'en', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
public languages: string[] = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
|
||||
public policy?: PasswordComplexityPolicy.AsObject;
|
||||
public usePassword: boolean = false;
|
||||
|
@ -437,6 +437,7 @@
|
||||
class="redirect-section"
|
||||
[disabled]="false"
|
||||
[(ngModel)]="redirectUris"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
[getValues]="requestRedirectValuesSubject$"
|
||||
title="{{ 'APP.OIDC.REDIRECT' | translate }}"
|
||||
[isNative]="appType?.value.oidcAppType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
@ -447,6 +448,7 @@
|
||||
class="redirect-section"
|
||||
[disabled]="false"
|
||||
[(ngModel)]="postLogoutUrisList"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}"
|
||||
[getValues]="requestRedirectValuesSubject$"
|
||||
[isNative]="appType?.value.oidcAppType === OIDCAppType.OIDC_APP_TYPE_NATIVE"
|
||||
|
@ -398,10 +398,10 @@
|
||||
|
||||
<ng-container *ngIf="currentSetting === 'urls'">
|
||||
<cnsl-card title=" {{ 'APP.URLS' | translate }}">
|
||||
<cnsl-info-section *ngIf="environmentMap?.issuer">
|
||||
<cnsl-info-section *ngIf="environmentMap['issuer']">
|
||||
<div
|
||||
[innerHtml]="
|
||||
'APP.OIDC.WELLKNOWN' | translate : { url: environmentMap.issuer + '/.well-known/openid-configuration' }
|
||||
'APP.OIDC.WELLKNOWN' | translate : { url: environmentMap['issuer'] + '/.well-known/openid-configuration' }
|
||||
"
|
||||
></div>
|
||||
</cnsl-info-section>
|
||||
|
@ -34,7 +34,7 @@ export class ProjectGrantCreateComponent implements OnInit, OnDestroy {
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
||||
this.projectId = params.projectid;
|
||||
this.projectId = params['projectid'];
|
||||
|
||||
const breadcrumbs = [
|
||||
new Breadcrumb({
|
||||
|
@ -49,19 +49,19 @@ export class ProjectGrantDetailComponent {
|
||||
private breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.route.params.subscribe((params) => {
|
||||
this.projectid = params.projectid;
|
||||
this.grantid = params.grantid;
|
||||
this.projectid = params['projectid'];
|
||||
this.grantid = params['grantid'];
|
||||
|
||||
this.dataSource = new ProjectGrantMembersDataSource(this.mgmtService);
|
||||
this.dataSource.loadMembers(params.projectid, params.grantid, 0, this.INITIALPAGESIZE);
|
||||
this.dataSource.loadMembers(params['projectid'], params['grantid'], 0, this.INITIALPAGESIZE);
|
||||
|
||||
this.getRoleOptions(params.projectid);
|
||||
this.getRoleOptions(params['projectid']);
|
||||
this.getMemberRoleOptions();
|
||||
|
||||
this.changePageFactory = (event?: PageEvent) => {
|
||||
return this.dataSource.loadMembers(
|
||||
params.projectid,
|
||||
params.grantid,
|
||||
params['projectid'],
|
||||
params['grantid'],
|
||||
event?.pageIndex ?? 0,
|
||||
event?.pageSize ?? this.INITIALPAGESIZE,
|
||||
);
|
||||
|
@ -24,7 +24,7 @@ export class ProjectsComponent {
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.activatedRoute.queryParams.pipe(take(1)).subscribe((params: Params) => {
|
||||
const type = params.type;
|
||||
const type = params['type'];
|
||||
if (type && type === 'owned') {
|
||||
this.setType(ProjectType.PROJECTTYPE_OWNED);
|
||||
} else if (type && type === 'granted') {
|
||||
|
@ -10,11 +10,11 @@
|
||||
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="machine-create-form">
|
||||
<div class="machine-create-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.MACHINE.USERNAME' | translate }}*</cnsl-label>
|
||||
<cnsl-label>{{ 'USER.MACHINE.USERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="userName" required />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.MACHINE.NAME' | translate }}*</cnsl-label>
|
||||
<cnsl-label>{{ 'USER.MACHINE.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" required />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
|
@ -13,11 +13,11 @@
|
||||
|
||||
<div class="user-create-grid">
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}*</cnsl-label>
|
||||
<cnsl-label>{{ 'USER.PROFILE.EMAIL' | translate }}</cnsl-label>
|
||||
<input cnslInput matRipple formControlName="email" required />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}*</cnsl-label>
|
||||
<cnsl-label>{{ 'USER.PROFILE.USERNAME' | translate }}</cnsl-label>
|
||||
<input
|
||||
cnslInput
|
||||
formControlName="userName"
|
||||
@ -28,11 +28,11 @@
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}*</cnsl-label>
|
||||
<cnsl-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="firstName" required />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.LASTNAME' | translate }}*</cnsl-label>
|
||||
<cnsl-label>{{ 'USER.PROFILE.LASTNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="lastName" required />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field>
|
||||
|
@ -33,7 +33,7 @@ import {
|
||||
export class UserCreateComponent implements OnInit, OnDestroy {
|
||||
public user: AddHumanUserRequest.AsObject = new AddHumanUserRequest().toObject();
|
||||
public genders: Gender[] = [Gender.GENDER_FEMALE, Gender.GENDER_MALE, Gender.GENDER_UNSPECIFIED];
|
||||
public languages: string[] = ['de', 'en', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
public languages: string[] = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
public selected: CountryPhoneCode | undefined;
|
||||
public countryPhoneCodes: CountryPhoneCode[] = [];
|
||||
public userForm!: UntypedFormGroup;
|
||||
|
@ -33,7 +33,7 @@ import { EditDialogComponent, EditDialogType } from './edit-dialog/edit-dialog.c
|
||||
export class AuthUserDetailComponent implements OnDestroy {
|
||||
public user?: User.AsObject;
|
||||
public genders: Gender[] = [Gender.GENDER_MALE, Gender.GENDER_FEMALE, Gender.GENDER_DIVERSE];
|
||||
public languages: string[] = ['de', 'en', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
public languages: string[] = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh'];
|
||||
|
||||
private subscription: Subscription = new Subscription();
|
||||
|
||||
|
@ -11,8 +11,8 @@ export class PhoneDetailComponent implements OnChanges {
|
||||
public country: string | undefined;
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.phone.currentValue) {
|
||||
const phoneNumber = formatPhone(changes.phone.currentValue);
|
||||
if (changes['phone'].currentValue) {
|
||||
const phoneNumber = formatPhone(changes['phone'].currentValue);
|
||||
if (this.phone !== phoneNumber.phone) {
|
||||
this.phone = phoneNumber.phone;
|
||||
this.country = phoneNumber.country;
|
||||
|
@ -44,7 +44,7 @@ export class UserDetailComponent implements OnInit {
|
||||
public user!: User.AsObject;
|
||||
public metadata: Metadata.AsObject[] = [];
|
||||
public genders: Gender[] = [Gender.GENDER_MALE, Gender.GENDER_FEMALE, Gender.GENDER_DIVERSE];
|
||||
public languages: string[] = ['de', 'en', 'it', 'fr', 'ja', 'pl', 'zh'];
|
||||
public languages: string[] = ['de', 'en', 'es', 'it', 'fr', 'ja', 'pl', 'zh'];
|
||||
|
||||
public ChangeType: any = ChangeType;
|
||||
|
||||
|
@ -96,7 +96,7 @@ export class UserTableComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
this.route.queryParams.pipe(take(1)).subscribe((params) => {
|
||||
this.getData(this.INITIAL_PAGE_SIZE, 0, this.type);
|
||||
if (params.deferredReload) {
|
||||
if (params['deferredReload']) {
|
||||
setTimeout(() => {
|
||||
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize, this.type);
|
||||
}, 2000);
|
||||
|
@ -22,7 +22,7 @@ export class LocalizedDatePipe implements PipeTransform {
|
||||
return moment(value).format(`${format}, HH:mm`);
|
||||
}
|
||||
} else {
|
||||
const lang = ['de', 'en', 'fr', 'it', 'ja', 'pl', 'zh'].includes(this.translateService.currentLang)
|
||||
const lang = ['de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'zh'].includes(this.translateService.currentLang)
|
||||
? this.translateService.currentLang
|
||||
: 'en';
|
||||
const datePipe: DatePipe = new DatePipe(lang);
|
||||
|
@ -1047,6 +1047,10 @@ export class AdminService {
|
||||
return this.grpcService.admin.getProviderByID(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getProviderID(req: GetProviderByIDRequest): Promise<GetProviderByIDResponse> {
|
||||
return this.grpcService.admin.getProviderByID(req, null);
|
||||
}
|
||||
|
||||
public listIAMMembers(
|
||||
limit: number,
|
||||
offset: number,
|
||||
|
@ -987,6 +987,10 @@ export class ManagementService {
|
||||
return this.grpcService.mgmt.getProviderByID(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getProviderID(req: GetProviderByIDRequest): Promise<GetProviderByIDResponse> {
|
||||
return this.grpcService.mgmt.getProviderByID(req, null);
|
||||
}
|
||||
|
||||
public addHumanUser(req: AddHumanUserRequest): Promise<AddHumanUserResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addHumanUser(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Meta } from '@angular/platform-browser';
|
||||
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
@ -14,7 +12,7 @@ export class SeoService {
|
||||
config = {
|
||||
title: 'ZITADEL Console',
|
||||
description: 'Managementplatform for ZITADEL',
|
||||
image: 'https://www.zitadel.ch/zitadel-social-preview25.png',
|
||||
image: 'https://www.zitadel.com/images/preview.png',
|
||||
slug: '',
|
||||
...config,
|
||||
};
|
||||
@ -27,15 +25,11 @@ export class SeoService {
|
||||
if (config.image) {
|
||||
this.meta.updateTag({ property: 'og:image', content: config.image });
|
||||
}
|
||||
this.meta.updateTag({
|
||||
property: 'og:url',
|
||||
content: `https://${environment.production ? 'console.zitadel.ch' : 'console.zitadel.dev'}/${config.slug}`,
|
||||
});
|
||||
|
||||
this.meta.updateTag({ property: 'twitter:card', content: 'summary' });
|
||||
this.meta.updateTag({ property: 'og:site', content: '@zitadel_ch' });
|
||||
this.meta.updateTag({ property: 'og:title', content: config.title });
|
||||
this.meta.updateTag({ property: 'og:image', content: 'https://www.zitadel.ch/zitadel-social-preview25.png' });
|
||||
this.meta.updateTag({ property: 'og:image', content: 'https://www.zitadel.com/images/preview.png' });
|
||||
this.meta.updateTag({ property: 'og:description', content: config.description });
|
||||
}
|
||||
}
|
||||
|
@ -247,6 +247,7 @@
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "Bitte fülle dieses Feld aus.",
|
||||
"ATLEASTONE": "Geben Sie mindestens einen Wert an.",
|
||||
"TOKENINVALID": {
|
||||
"TITLE": "Du bist abgemeldet",
|
||||
"DESCRIPTION": "Klicke auf \"Einloggen\", um Dich erneut anzumelden."
|
||||
@ -1019,6 +1020,7 @@
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1217,6 +1219,7 @@
|
||||
"LOCALES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1697,6 +1700,7 @@
|
||||
"2": "inaktiv"
|
||||
},
|
||||
"AZUREADTENANTTYPES": {
|
||||
"3": "Tenant ID",
|
||||
"0": "Common",
|
||||
"1": "Organizations",
|
||||
"2": "Consumers"
|
||||
@ -2078,6 +2082,7 @@
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
|
@ -248,6 +248,7 @@
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "Please fill in this field.",
|
||||
"ATLEASTONE": "Provide at least one value.",
|
||||
"TOKENINVALID": {
|
||||
"TITLE": "Your authorization token has expired.",
|
||||
"DESCRIPTION": "Click the button below to log in again."
|
||||
@ -1020,6 +1021,7 @@
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1149,6 +1151,10 @@
|
||||
"MAXSIZEEXCEEDED": "Maximum size of 524kB exceeded.",
|
||||
"NOSVGSUPPORTED": "SVG are not supported!",
|
||||
"FONTINLOGINONLY": "The font is currently only displayed in the login interface.",
|
||||
"BACKGROUNDCOLOR": "Background color",
|
||||
"PRIMARYCOLOR": "Primary color",
|
||||
"WARNCOLOR": "Warning color",
|
||||
"FONTCOLOR": "Font color",
|
||||
"VIEWS": {
|
||||
"PREVIEW": "Preview",
|
||||
"CURRENT": "Current Configuration"
|
||||
@ -1209,11 +1215,12 @@
|
||||
"RESET_TITLE": "Restore Default Values",
|
||||
"RESET_DESCRIPTION": "You are about to restore all default values. All changes you have made will be permanently deleted. Do you really want to continue?",
|
||||
"UNSAVED_TITLE": "Continue without saving?",
|
||||
"UNSAVED_DESCRIPTION": "Your have made changes without saving. Do you want to save now?",
|
||||
"UNSAVED_DESCRIPTION": "You have made changes without saving. Do you want to save now?",
|
||||
"LOCALE": "Locale Code",
|
||||
"LOCALES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1693,6 +1700,7 @@
|
||||
"2": "inactive"
|
||||
},
|
||||
"AZUREADTENANTTYPES": {
|
||||
"3": "Tenant ID",
|
||||
"0": "Common",
|
||||
"1": "Organizations",
|
||||
"2": "Consumers"
|
||||
@ -2071,6 +2079,7 @@
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
|
2162
console/src/assets/i18n/es.json
Normal file
2162
console/src/assets/i18n/es.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -247,6 +247,7 @@
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "Remplis ce champ s'il te plaît.",
|
||||
"ATLEASTONE": "Indiquez au moins une valeur.",
|
||||
"TOKENINVALID": {
|
||||
"TITLE": "Votre jeton d'autorisation a expiré.",
|
||||
"DESCRIPTION": "Cliquez sur le bouton ci-dessous pour vous reconnecter."
|
||||
@ -1019,6 +1020,7 @@
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1217,6 +1219,7 @@
|
||||
"LOCALES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1701,6 +1704,7 @@
|
||||
"2": "inactif"
|
||||
},
|
||||
"AZUREADTENANTTYPES": {
|
||||
"3": "Tenant ID",
|
||||
"0": "Common",
|
||||
"1": "Organizations",
|
||||
"2": "Consumers"
|
||||
@ -2067,6 +2071,7 @@
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
|
@ -247,6 +247,7 @@
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "Compilare questo campo.",
|
||||
"ATLEASTONE": "Inserisci almeno un valore.",
|
||||
"TOKENINVALID": {
|
||||
"TITLE": "Il tuo Access Token \u00e8 scaduto.",
|
||||
"DESCRIPTION": "Clicca il pulsante per richiedere una nuova sessione."
|
||||
@ -1020,6 +1021,7 @@
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1218,6 +1220,7 @@
|
||||
"LOCALES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1702,6 +1705,7 @@
|
||||
"2": "inattivo"
|
||||
},
|
||||
"AZUREADTENANTTYPES": {
|
||||
"3": "Tenant ID",
|
||||
"0": "Common",
|
||||
"1": "Organizations",
|
||||
"2": "Consumers"
|
||||
@ -2080,6 +2084,7 @@
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
|
@ -248,6 +248,7 @@
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "一部の必須項目が不足しています。",
|
||||
"ATLEASTONE": "少なくとも 1 つの値を指定してください。",
|
||||
"TOKENINVALID": {
|
||||
"TITLE": "トークンが期限切れになりました。",
|
||||
"DESCRIPTION": "下のボタンをクリックして、もう一度ログインする。"
|
||||
@ -1020,6 +1021,7 @@
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1213,6 +1215,7 @@
|
||||
"LOCALES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1692,9 +1695,10 @@
|
||||
"2": "非アクティブ"
|
||||
},
|
||||
"AZUREADTENANTTYPES": {
|
||||
"0": "共通",
|
||||
"1": "組織",
|
||||
"2": "顧客"
|
||||
"3": "Tenant ID",
|
||||
"0": "Common",
|
||||
"1": "Organizations",
|
||||
"2": "Consumers"
|
||||
},
|
||||
"AZUREADTENANTTYPE": "テナントタイプ",
|
||||
"AZUREADTENANTID": "テナントID",
|
||||
@ -2070,6 +2074,7 @@
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
|
@ -247,6 +247,7 @@
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "Proszę wypełnić to pole.",
|
||||
"ATLEASTONE": "Podaj co najmniej jedną wartość.",
|
||||
"TOKENINVALID": {
|
||||
"TITLE": "Twój token autoryzacji wygasł.",
|
||||
"DESCRIPTION": "Kliknij przycisk poniżej, aby ponownie się zalogować."
|
||||
@ -1019,6 +1020,7 @@
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1217,6 +1219,7 @@
|
||||
"LOCALES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1701,6 +1704,7 @@
|
||||
"2": "nieaktywny"
|
||||
},
|
||||
"AZUREADTENANTTYPES": {
|
||||
"3": "Tenant ID",
|
||||
"0": "Common",
|
||||
"1": "Organizations",
|
||||
"2": "Consumers"
|
||||
@ -2079,6 +2083,7 @@
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
|
@ -247,6 +247,7 @@
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "请填写此栏",
|
||||
"ATLEASTONE": "P至少提供一个值。",
|
||||
"TOKENINVALID": {
|
||||
"TITLE": "您的授权令牌已过期。",
|
||||
"DESCRIPTION": "点击下方按钮再次登录。"
|
||||
@ -1019,6 +1020,7 @@
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1216,6 +1218,7 @@
|
||||
"LOCALES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
@ -1700,6 +1703,7 @@
|
||||
"2": "停用"
|
||||
},
|
||||
"AZUREADTENANTTYPES": {
|
||||
"3": "Tenant ID",
|
||||
"0": "Common",
|
||||
"1": "Organizations",
|
||||
"2": "Consumers"
|
||||
@ -2066,6 +2070,7 @@
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
|
@ -1,3 +0,0 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
};
|
@ -1,16 +0,0 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
};
|
||||
|
||||
/*
|
||||
* For easier debugging in development mode, you can import the following file
|
||||
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||
*
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
@ -1,15 +1,6 @@
|
||||
import 'codemirror/mode/javascript/javascript';
|
||||
import 'codemirror/mode/xml/xml';
|
||||
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user