mirror of
https://github.com/zitadel/zitadel.git
synced 2025-04-16 19:51:47 +00:00
Merge branch 'next-rc' into next
This commit is contained in:
commit
5cbf34334f
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -91,7 +91,7 @@ jobs:
|
||||
pull-requests: write
|
||||
needs:
|
||||
[version, core-unit-test, core-integration-test, lint, container, e2e]
|
||||
if: ${{ needs.version.outputs.published == 'true' && github.event_name == 'workflow_dispatch' }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
secrets:
|
||||
GCR_JSON_KEY_BASE64: ${{ secrets.GCR_JSON_KEY_BASE64 }}
|
||||
with:
|
||||
|
2
.github/workflows/version.yml
vendored
2
.github/workflows/version.yml
vendored
@ -47,4 +47,4 @@ jobs:
|
||||
name: output
|
||||
id: output
|
||||
run:
|
||||
if [[ ! -z "${{ steps.semantic.outputs.new_release_version }}" ]]; then echo "VERSION=v${{ steps.semantic.outputs.new_release_version }}" >> "$GITHUB_OUTPUT"; else echo "VERSION=" >> "$GITHUB_OUTPUT";fi
|
||||
if [[ ! -z "${{ steps.semantic.outputs.new_release_version }}" ]]; then echo "VERSION=v${{ steps.semantic.outputs.new_release_version }}" >> "$GITHUB_OUTPUT"; else echo "VERSION=${{ github.sha }}" >> "$GITHUB_OUTPUT";fi
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -25,6 +25,7 @@ sandbox.go
|
||||
.idea
|
||||
.vscode
|
||||
.DS_STORE
|
||||
.run
|
||||
|
||||
# credential
|
||||
google-credentials
|
||||
@ -75,6 +76,7 @@ migrations/cockroach/migrate_cloud.go
|
||||
!/.artifacts/zitadel
|
||||
/zitadel
|
||||
node_modules/
|
||||
.kreya
|
||||
|
||||
go.work
|
||||
go.work.sum
|
||||
|
2
Makefile
2
Makefile
@ -103,7 +103,7 @@ core_unit_test:
|
||||
core_integration_setup:
|
||||
go build -o zitadel main.go
|
||||
./zitadel init --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml
|
||||
./zitadel setup --masterkeyFromEnv --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml
|
||||
./zitadel setup --masterkeyFromEnv --config internal/integration/config/zitadel.yaml --config internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml --steps internal/integration/config/zitadel.yaml --steps internal/integration/config/${INTEGRATION_DB_FLAVOR}.yaml
|
||||
$(RM) zitadel
|
||||
|
||||
.PHONY: core_integration_test
|
||||
|
@ -721,11 +721,11 @@ DefaultInstance:
|
||||
Host: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST
|
||||
User: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_USER
|
||||
Password: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_PASSWORD
|
||||
TLS: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_SSL
|
||||
TLS: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_TLS
|
||||
# If the host of the sender is different from ExternalDomain set DefaultInstance.DomainPolicy.SMTPSenderAddressMatchesInstanceDomain to false
|
||||
From: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROM
|
||||
FromName: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_FROMNAME
|
||||
ReplyToAddress: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_REPLYTOADDRESS
|
||||
From: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_FROM
|
||||
FromName: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_FROMNAME
|
||||
ReplyToAddress: # ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_REPLYTOADDRESS
|
||||
MessageTexts:
|
||||
- MessageTextType: InitCode
|
||||
Language: de
|
||||
@ -834,6 +834,11 @@ DefaultInstance:
|
||||
# DisallowPublicOrgRegistration defines if ZITADEL should expose the endpoint /ui/login/register/org
|
||||
# If it is true, the endpoint returns the HTTP status 404 on GET requests, and 409 on POST requests.
|
||||
DisallowPublicOrgRegistration: # ZITADEL_DEFAULTINSTANCE_RESTRICTIONS_DISALLOWPUBLICORGREGISTRATION
|
||||
# AllowedLanguages restricts the languages that can be used.
|
||||
# If the list is empty, all supported languages are allowed.
|
||||
AllowedLanguages: # ZITADEL_DEFAULTINSTANCE_RESTRICTIONS_ALLOWEDLANGUAGES
|
||||
# - en
|
||||
# - de
|
||||
Quotas:
|
||||
# Items take a slice of quota configurations, whereas, for each unit type and instance, one or zero quotas may exist.
|
||||
# The following unit types are supported
|
||||
|
@ -1,2 +1,2 @@
|
||||
-- replace %[1]s with the name of the user
|
||||
CREATE USER IF NOT EXISTS %[1]s
|
||||
CREATE USER IF NOT EXISTS "%[1]s"
|
@ -1,2 +1,2 @@
|
||||
-- replace %[1]s with the name of the database
|
||||
CREATE DATABASE IF NOT EXISTS %[1]s
|
||||
CREATE DATABASE IF NOT EXISTS "%[1]s"
|
@ -1,4 +1,4 @@
|
||||
-- replace the first %[1]s with the database
|
||||
-- replace the second \%[2]s with the user
|
||||
GRANT ALL ON DATABASE %[1]s TO %[2]s;
|
||||
GRANT SYSTEM VIEWACTIVITY TO %[2]s;
|
||||
GRANT ALL ON DATABASE "%[1]s" TO "%[2]s";
|
||||
GRANT SYSTEM VIEWACTIVITY TO "%[2]s";
|
@ -1,3 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS eventstore;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA eventstore TO %[1]s;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA eventstore TO "%[1]s";
|
@ -1,3 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS projections;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA projections TO %[1]s;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA projections TO "%[1]s";
|
@ -1,3 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS system;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA system TO %[1]s;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA system TO "%[1]s";
|
@ -1 +1 @@
|
||||
CREATE USER %[1]s
|
||||
CREATE USER "%[1]s"
|
@ -1 +1 @@
|
||||
CREATE DATABASE %[1]s
|
||||
CREATE DATABASE "%[1]s"
|
@ -1,3 +1,3 @@
|
||||
-- replace the first %[1]s with the database
|
||||
-- replace the second \%[2]s with the user
|
||||
GRANT ALL ON DATABASE %[1]s TO %[2]s;
|
||||
GRANT ALL ON DATABASE "%[1]s" TO "%[2]s";
|
@ -1,3 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS eventstore;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA eventstore TO %[1]s;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA eventstore TO "%[1]s";
|
@ -1,3 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS projections;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA projections TO %[1]s;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA projections TO "%[1]s";
|
@ -1,3 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS system;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA system TO %[1]s;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA system TO "%[1]s";
|
@ -26,7 +26,7 @@ func Test_verifyDB(t *testing.T) {
|
||||
name: "doesn't exists, create fails",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS zitadel", sql.ErrTxDone),
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS \"zitadel\"", sql.ErrTxDone),
|
||||
),
|
||||
database: "zitadel",
|
||||
},
|
||||
@ -36,7 +36,7 @@ func Test_verifyDB(t *testing.T) {
|
||||
name: "doesn't exists, create successful",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS zitadel", nil),
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS \"zitadel\"", nil),
|
||||
),
|
||||
database: "zitadel",
|
||||
},
|
||||
@ -46,7 +46,7 @@ func Test_verifyDB(t *testing.T) {
|
||||
name: "already exists",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS zitadel", nil),
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS \"zitadel\"", nil),
|
||||
),
|
||||
database: "zitadel",
|
||||
},
|
||||
|
@ -21,7 +21,7 @@ func Test_verifyGrant(t *testing.T) {
|
||||
name: "doesn't exists, create fails",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("GRANT ALL ON DATABASE zitadel TO zitadel-user", sql.ErrTxDone),
|
||||
expectExec("GRANT ALL ON DATABASE \"zitadel\" TO \"zitadel-user\"", sql.ErrTxDone),
|
||||
),
|
||||
database: "zitadel",
|
||||
username: "zitadel-user",
|
||||
@ -32,7 +32,7 @@ func Test_verifyGrant(t *testing.T) {
|
||||
name: "correct",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("GRANT ALL ON DATABASE zitadel TO zitadel-user", nil),
|
||||
expectExec("GRANT ALL ON DATABASE \"zitadel\" TO \"zitadel-user\"", nil),
|
||||
),
|
||||
database: "zitadel",
|
||||
username: "zitadel-user",
|
||||
@ -43,7 +43,7 @@ func Test_verifyGrant(t *testing.T) {
|
||||
name: "already exists",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("GRANT ALL ON DATABASE zitadel TO zitadel-user", nil),
|
||||
expectExec("GRANT ALL ON DATABASE \"zitadel\" TO \"zitadel-user\"", nil),
|
||||
),
|
||||
database: "zitadel",
|
||||
username: "zitadel-user",
|
||||
|
@ -27,7 +27,7 @@ func Test_verifyUser(t *testing.T) {
|
||||
name: "doesn't exists, create fails",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS zitadel-user", sql.ErrTxDone),
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS \"zitadel-user\"", sql.ErrTxDone),
|
||||
),
|
||||
username: "zitadel-user",
|
||||
password: "",
|
||||
@ -38,7 +38,7 @@ func Test_verifyUser(t *testing.T) {
|
||||
name: "correct without password",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS zitadel-user", nil),
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS \"zitadel-user\"", nil),
|
||||
),
|
||||
username: "zitadel-user",
|
||||
password: "",
|
||||
@ -49,7 +49,7 @@ func Test_verifyUser(t *testing.T) {
|
||||
name: "correct with password",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS zitadel-user WITH PASSWORD 'password'", nil),
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS \"zitadel-user\" WITH PASSWORD 'password'", nil),
|
||||
),
|
||||
username: "zitadel-user",
|
||||
password: "password",
|
||||
@ -60,7 +60,7 @@ func Test_verifyUser(t *testing.T) {
|
||||
name: "already exists",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS zitadel-user WITH PASSWORD 'password'", nil),
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS \"zitadel-user\" WITH PASSWORD 'password'", nil),
|
||||
),
|
||||
username: "zitadel-user",
|
||||
password: "",
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
cryptoDB "github.com/zitadel/zitadel/internal/crypto/database"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/database/dialect"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -86,7 +86,7 @@ func keysFromArgs(args []string) ([]*crypto.Key, error) {
|
||||
for i, arg := range args {
|
||||
key := strings.Split(arg, "=")
|
||||
if len(key) != 2 {
|
||||
return nil, caos_errs.ThrowInternal(nil, "KEY-JKd82", "argument is not in the valid format [keyID=key]")
|
||||
return nil, zerrors.ThrowInternal(nil, "KEY-JKd82", "argument is not in the valid format [keyID=key]")
|
||||
}
|
||||
keys[i] = &crypto.Key{
|
||||
ID: key[0],
|
||||
@ -99,11 +99,11 @@ func keysFromArgs(args []string) ([]*crypto.Key, error) {
|
||||
func keysFromYAML(file io.Reader) ([]*crypto.Key, error) {
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, caos_errs.ThrowInternal(err, "KEY-ajGFr", "unable to extract keys from file")
|
||||
return nil, zerrors.ThrowInternal(err, "KEY-ajGFr", "unable to extract keys from file")
|
||||
}
|
||||
keysYAML := make(map[string]string)
|
||||
if err = yaml.Unmarshal(data, &keysYAML); err != nil {
|
||||
return nil, caos_errs.ThrowInternal(err, "KEY-sd34K", "unable to extract keys from file")
|
||||
return nil, zerrors.ThrowInternal(err, "KEY-sd34K", "unable to extract keys from file")
|
||||
}
|
||||
keys := make([]*crypto.Key, 0, len(keysYAML))
|
||||
for id, key := range keysYAML {
|
||||
@ -118,7 +118,7 @@ func keysFromYAML(file io.Reader) ([]*crypto.Key, error) {
|
||||
func openFile(fileName string) (io.Reader, error) {
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return nil, caos_errs.ThrowInternalf(err, "KEY-asGr2", "failed to open file: %s", fileName)
|
||||
return nil, zerrors.ThrowInternalf(err, "KEY-asGr2", "failed to open file: %s", fileName)
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
@ -8,9 +8,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func Test_keysFromArgs(t *testing.T) {
|
||||
@ -39,7 +38,7 @@ func Test_keysFromArgs(t *testing.T) {
|
||||
args: []string{"keyID", "value"},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsInternal,
|
||||
err: zerrors.IsInternal,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -110,7 +109,7 @@ func Test_keysFromYAML(t *testing.T) {
|
||||
file: bytes.NewReader([]byte("keyID=ds")),
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsInternal,
|
||||
err: zerrors.IsInternal,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1,3 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS logstore;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA logstore TO %[1]s;
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA logstore TO "%[1]s";
|
||||
|
26
cmd/setup/19.go
Normal file
26
cmd/setup/19.go
Normal file
@ -0,0 +1,26 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed 19.sql
|
||||
addCurrentSequencesIndex string
|
||||
)
|
||||
|
||||
type AddCurrentSequencesIndex struct {
|
||||
dbClient *database.DB
|
||||
}
|
||||
|
||||
func (mig *AddCurrentSequencesIndex) Execute(ctx context.Context) error {
|
||||
_, err := mig.dbClient.ExecContext(ctx, addCurrentSequencesIndex)
|
||||
return err
|
||||
}
|
||||
|
||||
func (mig *AddCurrentSequencesIndex) String() string {
|
||||
return "19_add_current_sequences_index"
|
||||
}
|
1
cmd/setup/19.sql
Normal file
1
cmd/setup/19.sql
Normal file
@ -0,0 +1 @@
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS events2_current_sequence ON eventstore.events2 ("sequence" DESC, aggregate_id, aggregate_type, instance_id);
|
@ -76,6 +76,7 @@ type Steps struct {
|
||||
s16UniqueConstraintsLower *UniqueConstraintToLower
|
||||
s17AddOffsetToUniqueConstraints *AddOffsetToCurrentStates
|
||||
s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames
|
||||
s19AddCurrentStatesIndex *AddCurrentSequencesIndex
|
||||
}
|
||||
|
||||
type encryptionKeyConfig struct {
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
old_es "github.com/zitadel/zitadel/internal/eventstore/repository/sql"
|
||||
new_es "github.com/zitadel/zitadel/internal/eventstore/v3"
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
"github.com/zitadel/zitadel/internal/migration"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
)
|
||||
@ -65,6 +66,8 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
ctx := context.Background()
|
||||
logging.Info("setup started")
|
||||
|
||||
i18n.MustLoadSupportedLanguagesFromDir()
|
||||
|
||||
queryDBClient, err := database.Connect(config.Database, false, dialect.DBPurposeQuery)
|
||||
logging.OnError(err).Fatal("unable to connect to database")
|
||||
esPusherDBClient, err := database.Connect(config.Database, false, dialect.DBPurposeEventPusher)
|
||||
@ -106,6 +109,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
steps.s16UniqueConstraintsLower = &UniqueConstraintToLower{dbClient: queryDBClient}
|
||||
steps.s17AddOffsetToUniqueConstraints = &AddOffsetToCurrentStates{dbClient: queryDBClient}
|
||||
steps.s18AddLowerFieldsToLoginNames = &AddLowerFieldsToLoginNames{dbClient: queryDBClient}
|
||||
steps.s19AddCurrentStatesIndex = &AddCurrentSequencesIndex{dbClient: queryDBClient}
|
||||
|
||||
err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil)
|
||||
logging.OnError(err).Fatal("unable to start projections")
|
||||
@ -150,6 +154,8 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
logging.WithFields("name", steps.s16UniqueConstraintsLower.String()).OnError(err).Fatal("migration failed")
|
||||
err = migration.Migrate(ctx, eventstoreClient, steps.s17AddOffsetToUniqueConstraints)
|
||||
logging.WithFields("name", steps.s17AddOffsetToUniqueConstraints.String()).OnError(err).Fatal("migration failed")
|
||||
err = migration.Migrate(ctx, eventstoreClient, steps.s19AddCurrentStatesIndex)
|
||||
logging.WithFields("name", steps.s19AddCurrentStatesIndex.String()).OnError(err).Fatal("migration failed")
|
||||
|
||||
for _, repeatableStep := range repeatableSteps {
|
||||
err = migration.Migrate(ctx, eventstoreClient, repeatableStep)
|
||||
|
@ -2,7 +2,7 @@ package start
|
||||
|
||||
import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -106,7 +106,7 @@ func verifyDefaultKeys(keyStorage crypto.KeyStorage) (err error) {
|
||||
return nil
|
||||
}
|
||||
if err := keyStorage.CreateKeys(keys...); err != nil {
|
||||
return caos_errs.ThrowInternal(err, "START-aGBq2", "cannot create default keys")
|
||||
return zerrors.ThrowInternal(err, "START-aGBq2", "cannot create default keys")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
old_es "github.com/zitadel/zitadel/internal/eventstore/repository/sql"
|
||||
new_es "github.com/zitadel/zitadel/internal/eventstore/v3"
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
"github.com/zitadel/zitadel/internal/logstore"
|
||||
"github.com/zitadel/zitadel/internal/logstore/emitters/access"
|
||||
@ -94,7 +95,6 @@ Requirements:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return startZitadel(config, masterKey, server)
|
||||
},
|
||||
}
|
||||
@ -124,6 +124,8 @@ func startZitadel(config *Config, masterKey string, server chan<- *Server) error
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
i18n.MustLoadSupportedLanguagesFromDir()
|
||||
|
||||
queryDBClient, err := database.Connect(config.Database, false, dialect.DBPurposeQuery)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot start DB client for queries: %w", err)
|
||||
@ -221,6 +223,7 @@ func startZitadel(config *Config, masterKey string, server chan<- *Server) error
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot start commands: %w", err)
|
||||
}
|
||||
defer commands.Close(ctx) // wait for background jobs
|
||||
|
||||
clock := clockpkg.New()
|
||||
actionsExecutionStdoutEmitter, err := logstore.NewEmitter[*record.ExecutionLog](ctx, clock, &logstore.EmitterConfig{Enabled: config.LogStore.Execution.Stdout.Enabled}, stdout.NewStdoutEmitter[*record.ExecutionLog]())
|
||||
|
@ -69,6 +69,7 @@ import { StatehandlerService, StatehandlerServiceImpl } from './services/stateha
|
||||
import { StorageService } from './services/storage.service';
|
||||
import { ThemeService } from './services/theme.service';
|
||||
import { ToastService } from './services/toast.service';
|
||||
import { LanguagesService } from './services/languages.service';
|
||||
|
||||
registerLocaleData(localeDe);
|
||||
i18nIsoCountries.registerLocale(require('i18n-iso-countries/langs/de.json'));
|
||||
@ -228,6 +229,7 @@ const authConfig: AuthConfig = {
|
||||
AssetService,
|
||||
ToastService,
|
||||
NavigationService,
|
||||
LanguagesService,
|
||||
{ provide: 'windowObject', useValue: window },
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
|
@ -1,64 +1,87 @@
|
||||
<span class="title" mat-dialog-title>{{ 'ORG.PAGES.ORGDOMAIN.TITLE' | translate }} {{ domain?.domainName }}</span>
|
||||
<div mat-dialog-content>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION' | translate }}</p>
|
||||
<div mat-dialog-title>
|
||||
<div class="dialog-title">
|
||||
<h2>{{ 'ORG.PAGES.ORGDOMAIN.TITLE' | translate: { value: domain?.domainName } }}</h2>
|
||||
<a
|
||||
mat-icon-button
|
||||
href="https://zitadel.com/docs/guides/manage/console/organizations#verify-your-domain-name"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
aria-label="docs"
|
||||
>
|
||||
<mat-icon class="icon">info_outline</mat-icon>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<cnsl-info-section [type]="InfoSectionType.WARN" class="desc">{{
|
||||
<div mat-dialog-content cdkFocusInitial autofocus>
|
||||
<div *ngIf="showNew && !(dns || http)">
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION' | translate }}</p>
|
||||
<p class="desc">
|
||||
{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTML' | translate }}
|
||||
</p>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS' | translate }}</p>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_SKIP' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<cnsl-info-section [type]="InfoSectionType.WARN" *ngIf="showNew && !(dns || http)" class="desc">{{
|
||||
'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_DESC' | translate
|
||||
}}</cnsl-info-section>
|
||||
|
||||
<p
|
||||
*ngIf="domain?.validationType !== DomainValidationType.DOMAIN_VALIDATION_TYPE_UNSPECIFIED && !(dns || http)"
|
||||
class="desc"
|
||||
>
|
||||
{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_ONGOING' | translate: domain }}
|
||||
{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_ONGOING_TYPE' | translate }}
|
||||
{{ 'ORG.PAGES.ORGDOMAIN.TYPES.' + domain?.validationType | translate }}
|
||||
<p *ngIf="!showNew && !(dns || http)" class="desc">
|
||||
{{
|
||||
'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_ONGOING'
|
||||
| translate: { value: domain?.validationType == 1 ? 'HTTP' : 'DNS' }
|
||||
}}
|
||||
</p>
|
||||
|
||||
<div class="btn-container">
|
||||
<button
|
||||
[disabled]="domain?.validationType === DomainValidationType.DOMAIN_VALIDATION_TYPE_UNSPECIFIED"
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
*ngIf="!(dns || http)"
|
||||
(click)="validate()"
|
||||
>
|
||||
{{ 'ACTIONS.VERIFY' | translate }}
|
||||
</button>
|
||||
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
|
||||
<button *ngIf="!showNew" mat-stroked-button color="primary" (click)="showNew = true">
|
||||
{{ 'ORG.PAGES.ORGDOMAIN.REQUESTNEWTOKEN' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="showNew">
|
||||
<p>{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_NEWTOKEN_TITLE' | translate }}</p>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_NEWTOKEN_DESC' | translate }}</p>
|
||||
|
||||
<div class="btn-container" *ngIf="!(http || dns)">
|
||||
<button color="primary" mat-raised-button (click)="loadHttpToken()">HTTP</button>
|
||||
<button color="primary" mat-raised-button (click)="loadDnsToken()">DNS</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="http">
|
||||
<p>HTTP TOKEN</p>
|
||||
<p class="entry">{{ http.url }}</p>
|
||||
|
||||
<div class="btn-container">
|
||||
<button mat-stroked-button (click)="saveFile()" color="primary">{{ 'ORG.PAGES.DOWNLOAD_FILE' | translate }}</button>
|
||||
<button color="primary" class="verify-button" type="submit" mat-raised-button (click)="validate()">
|
||||
<span>{{ 'ACTIONS.VERIFY' | translate }}</span>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_DESC' | translate: { value: domain?.domainName } }}</p>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_URL_LABEL' | translate }}</p>
|
||||
<div class="domain-entry" *ngIf="http.url">
|
||||
<p>{{ http.url }}</p>
|
||||
<button
|
||||
color="primary"
|
||||
[disabled]="copied === data.clientSecret"
|
||||
matTooltip="copy to clipboard"
|
||||
cnslCopyToClipboard
|
||||
[valueToCopy]="http.url"
|
||||
(copiedValue)="copied = $event"
|
||||
mat-icon-button
|
||||
>
|
||||
<i *ngIf="copied !== http.url" class="las la-clipboard"></i>
|
||||
<i *ngIf="copied === http.url" class="las la-clipboard-check"></i>
|
||||
</button>
|
||||
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_HTTP_FILE_LABEL' | translate }}</p>
|
||||
<button mat-stroked-button (click)="saveFile()" color="primary">{{ 'ORG.PAGES.DOWNLOAD_FILE' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="dns">
|
||||
<p>DNS TOKEN</p>
|
||||
<div class="domain-line" *ngIf="dns.token">
|
||||
<p class="entry">{{ dns.token }}</p>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_DESC' | translate: { value: domain?.domainName } }}</p>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_HOST_LABEL' | translate }}</p>
|
||||
<div class="domain-line">
|
||||
<div class="domain-entry" *ngIf="dns.token">
|
||||
<p>{{ dnsChallenge }}</p>
|
||||
<button
|
||||
color="primary"
|
||||
[disabled]="copied === data.clientSecret"
|
||||
matTooltip="copy to clipboard"
|
||||
cnslCopyToClipboard
|
||||
[valueToCopy]="dnsChallenge"
|
||||
(copiedValue)="copied = $event"
|
||||
mat-icon-button
|
||||
>
|
||||
<i *ngIf="copied !== dnsChallenge" class="las la-clipboard"></i>
|
||||
<i *ngIf="copied === dnsChallenge" class="las la-clipboard-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
<span>.{{ domain?.domainName }}</span>
|
||||
</div>
|
||||
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_DNS_CHALLENGE_LABEL' | translate }}</p>
|
||||
<div class="domain-entry" *ngIf="dns.token">
|
||||
<p>{{ dns.token }}</p>
|
||||
<button
|
||||
color="primary"
|
||||
[disabled]="copied === data.clientSecret"
|
||||
@ -71,16 +94,32 @@
|
||||
<i *ngIf="copied !== dns.token" class="las la-clipboard"></i>
|
||||
<i *ngIf="copied === dns.token" class="las la-clipboard-check"></i>
|
||||
</button>
|
||||
<button color="primary" type="submit" mat-raised-button class="verify-button" (click)="validate()">
|
||||
{{ 'ACTIONS.VERIFY' | translate }}
|
||||
</button>
|
||||
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
</div>
|
||||
<p class="entry">{{ dns.url }}</p>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button
|
||||
*ngIf="!showNew || dns || http"
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
class="verify-button"
|
||||
(click)="validate()"
|
||||
>
|
||||
{{ 'ACTIONS.VERIFY' | translate }}
|
||||
</button>
|
||||
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
|
||||
<button *ngIf="!showNew" mat-stroked-button color="primary" (click)="showNew = true">
|
||||
{{ 'ORG.PAGES.ORGDOMAIN.RESETMETHOD' | translate }}
|
||||
</button>
|
||||
|
||||
<div>
|
||||
<button color="primary" *ngIf="showNew && !(dns || http)" mat-raised-button (click)="loadHttpToken()">HTTP</button>
|
||||
<button color="primary" *ngIf="showNew && !(dns || http)" mat-raised-button (click)="loadDnsToken()">DNS</button>
|
||||
</div>
|
||||
|
||||
<button mat-stroked-button (click)="closeDialog()">
|
||||
{{ 'ACTIONS.CLOSE' | translate }}
|
||||
</button>
|
||||
|
@ -1,28 +1,44 @@
|
||||
.btn-container {
|
||||
display: flex;
|
||||
margin: -0.5rem;
|
||||
align-items: center;
|
||||
@mixin domain-verification-theme($theme) {
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$border-color: if($is-dark-theme, rgba(#8795a1, 0.2), rgba(#8795a1, 0.2));
|
||||
|
||||
button {
|
||||
margin: 1rem 0.5rem;
|
||||
.desc {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.entry {
|
||||
margin: 0.5rem 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.domain-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
border: 1px solid $border-color;
|
||||
|
||||
p {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.domain-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
padding-left: 0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex !important;
|
||||
justify-content: space-between !important;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: -3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.entry {
|
||||
margin: 0.5rem 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.domain-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ export class DomainVerificationComponent {
|
||||
|
||||
public validating: boolean = false;
|
||||
public InfoSectionType: any = InfoSectionType;
|
||||
public dnsChallenge = '_zitadel-challenge';
|
||||
|
||||
constructor(
|
||||
private toast: ToastService,
|
||||
|
@ -145,7 +145,6 @@
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-events-section">
|
||||
<div class="checkbox-wrapper">
|
||||
<mat-checkbox id="sequenceFilterSet" name="sequenceFilterSet" class="cb" formControlName="sequenceFilterSet"
|
||||
@ -153,47 +152,74 @@
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div class="filter-events-sub" *ngIf="sequenceFilterSet?.value">
|
||||
<cnsl-form-field class="aggregate-type-select">
|
||||
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.SORT' | translate }}</cnsl-label>
|
||||
|
||||
<mat-select id="isAsc" name="isAsc" formControlName="isAsc">
|
||||
<mat-option [value]="false"> {{ 'IAM.EVENTS.FILTERS.SEQUENCE.DESC' | translate }} </mat-option>
|
||||
<mat-option [value]="true">{{ 'IAM.EVENTS.FILTERS.SEQUENCE.ASC' | translate }} </mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="filter-input-value">
|
||||
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SEQUENCE.LABEL' | translate }}</cnsl-label>
|
||||
<input cnslInput id="sequence" name="sequence" formControlName="sequence" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-events-section">
|
||||
<div class="checkbox-wrapper">
|
||||
<mat-checkbox
|
||||
id="creationDateFilterSet"
|
||||
name="creationDateFilterSet"
|
||||
class="cb"
|
||||
formControlName="creationDateFilterSet"
|
||||
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.CHECKBOX' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div class="filter-events-sub" *ngIf="creationDateFilterSet?.value">
|
||||
<cnsl-form-field class="filter-input-value">
|
||||
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL' | translate }}</cnsl-label>
|
||||
<input
|
||||
cnslInput
|
||||
id="creationDate"
|
||||
name="creationDate"
|
||||
[matDatepicker]="picker"
|
||||
formControlName="creationDate"
|
||||
/>
|
||||
<mat-datepicker-toggle style="top: 0" cnslSuffix [for]="picker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker></mat-datepicker>
|
||||
</cnsl-form-field>
|
||||
<mat-radio-group aria-label="Select an option" class="filter-events-sub" formControlName="creationDateFilterType">
|
||||
<mat-radio-button [value]="CreationDateFilterType.FROM">
|
||||
{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.RADIO_FROM' | translate }}
|
||||
</mat-radio-button>
|
||||
<mat-radio-button [value]="CreationDateFilterType.RANGE">
|
||||
{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.RADIO_RANGE' | translate }}
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
<div class="filter-events-sub">
|
||||
<ng-container *ngIf="creationDateFilterType!.value === CreationDateFilterType.FROM">
|
||||
<mat-form-field class="datetime-input">
|
||||
<input
|
||||
class="datetime"
|
||||
matInput
|
||||
type="datetime-local"
|
||||
name="creationDateFrom"
|
||||
[value]="creationDateFrom!.value | date: 'yyyy-MM-dd HH:mm:ss'"
|
||||
(change)="creationDateFrom = $event.target"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="creationDateFilterType!.value === CreationDateFilterType.RANGE">
|
||||
<div class="datetime-range">
|
||||
<mat-form-field class="datetime-input">
|
||||
<cnsl-label
|
||||
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL_SINCE' | translate }}
|
||||
<input
|
||||
matInput
|
||||
type="datetime-local"
|
||||
name="creationDateSince"
|
||||
[value]="creationDateSince!.value | date: 'yyyy-MM-dd HH:mm:ss'"
|
||||
(change)="creationDateSince = $event.target"
|
||||
/>
|
||||
</cnsl-label>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="datetime-input">
|
||||
<cnsl-label
|
||||
>{{ 'IAM.EVENTS.FILTERS.CREATIONDATE.LABEL_UNTIL' | translate }}
|
||||
<input
|
||||
matInput
|
||||
type="datetime-local"
|
||||
name="creationDateUntil"
|
||||
[value]="creationDateUntil!.value | date: 'yyyy-MM-dd HH:mm:ss'"
|
||||
(change)="creationDateUntil = $event.target"
|
||||
/>
|
||||
</cnsl-label>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-events-section">
|
||||
<cnsl-form-field class="aggregate-type-select">
|
||||
<cnsl-label>{{ 'IAM.EVENTS.FILTERS.SORT' | translate }}</cnsl-label>
|
||||
|
||||
<mat-select id="isAsc" name="isAsc" formControlName="isAsc">
|
||||
<mat-option [value]="false"> {{ 'IAM.EVENTS.FILTERS.DESC' | translate }} </mat-option>
|
||||
<mat-option [value]="true">{{ 'IAM.EVENTS.FILTERS.ASC' | translate }} </mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
@ -19,7 +19,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem 0;
|
||||
min-width: 320px;
|
||||
min-width: 360px;
|
||||
max-width: 360px;
|
||||
padding-bottom: 0.5rem;
|
||||
position: relative;
|
||||
@ -55,11 +55,23 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mdc-text-field--filled:not(.mdc-text-field--disabled) {
|
||||
background-color: map-get($background, cards);
|
||||
}
|
||||
|
||||
.datetime-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.datetime-range {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.filter-events-sub {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: space-around;
|
||||
padding: 0 0.5rem;
|
||||
background-color: if($is-dark-theme, #00000020, #00000008);
|
||||
margin: 0 -0.5rem;
|
||||
|
@ -15,13 +15,18 @@ export enum UserTarget {
|
||||
EXTERNAL = 'external',
|
||||
}
|
||||
|
||||
enum CreationDateFilterType {
|
||||
FROM = 'from',
|
||||
RANGE = 'range',
|
||||
}
|
||||
|
||||
function dateToTs(date: Date): Timestamp {
|
||||
const ts = new Timestamp();
|
||||
const milliseconds = date.getTime();
|
||||
const seconds = Math.abs(milliseconds / 1000);
|
||||
const seconds = milliseconds / 1000;
|
||||
const nanos = (milliseconds - seconds * 1000) * 1000 * 1000;
|
||||
ts.setSeconds(seconds);
|
||||
ts.setNanos(nanos);
|
||||
ts.setSeconds(Math.round(seconds));
|
||||
ts.setNanos(Math.round(nanos));
|
||||
return ts;
|
||||
}
|
||||
|
||||
@ -31,6 +36,9 @@ function dateToTs(date: Date): Timestamp {
|
||||
styleUrls: ['./filter-events.component.scss'],
|
||||
})
|
||||
export class FilterEventsComponent implements OnInit {
|
||||
// Make enum available in template
|
||||
public CreationDateFilterType = CreationDateFilterType;
|
||||
|
||||
public showFilter: boolean = false;
|
||||
public ActionKeysType: any = ActionKeysType;
|
||||
|
||||
@ -53,8 +61,11 @@ export class FilterEventsComponent implements OnInit {
|
||||
sequenceFilterSet: new FormControl(false),
|
||||
sequence: new FormControl(''),
|
||||
isAsc: new FormControl<boolean>(false),
|
||||
creationDateFilterSet: new FormControl(false),
|
||||
creationDate: new FormControl<Date>(new Date()),
|
||||
creationDateFilterType: new FormControl(CreationDateFilterType.FROM),
|
||||
creationDateFrom: new FormControl<Date>(new Date()),
|
||||
// creationDateSince is 15 minutes in the past by default
|
||||
creationDateSince: new FormControl<Date>(new Date(new Date().getTime() - 15 * 60_000)),
|
||||
creationDateUntil: new FormControl<Date>(new Date()),
|
||||
userFilterSet: new FormControl(false),
|
||||
editorUserId: new FormControl(''),
|
||||
aggregateFilterSet: new FormControl(false),
|
||||
@ -64,6 +75,8 @@ export class FilterEventsComponent implements OnInit {
|
||||
eventTypesList: new FormControl<EventType.AsObject[]>([]),
|
||||
});
|
||||
|
||||
private initialValues = this.form.getRawValue();
|
||||
|
||||
constructor(
|
||||
private adminService: AdminService,
|
||||
private toast: ToastService,
|
||||
@ -78,20 +91,35 @@ export class FilterEventsComponent implements OnInit {
|
||||
const { filter } = params;
|
||||
if (filter) {
|
||||
const stringifiedFilters = filter as string;
|
||||
const filters = JSON.parse(stringifiedFilters);
|
||||
const filters = JSON.parse(decodeURIComponent(stringifiedFilters));
|
||||
|
||||
if (filters.aggregateId) {
|
||||
this.request.setAggregateId(filters.aggregateId);
|
||||
this.aggregateId?.setValue(filters.aggregateId);
|
||||
this.aggregateFilterSet?.setValue(true);
|
||||
}
|
||||
if (filters.creationDate) {
|
||||
const milliseconds = filters.creationDate;
|
||||
const date = new Date(milliseconds);
|
||||
const ts = dateToTs(date);
|
||||
if (filters.creationDateFrom) {
|
||||
const millisecondsFrom = filters.creationDateFrom;
|
||||
const dateFrom = new Date(millisecondsFrom);
|
||||
const ts = dateToTs(dateFrom);
|
||||
this.creationDateFrom?.setValue(dateFrom);
|
||||
this.creationDateFilterType?.setValue(CreationDateFilterType.FROM);
|
||||
this.request.setCreationDate(ts);
|
||||
this.creationDate?.setValue(date);
|
||||
this.creationDateFilterSet?.setValue(true);
|
||||
}
|
||||
if (filters.creationDateSince || filters.creationDateUntil) {
|
||||
const millisecondsFrom = filters.creationDateSince;
|
||||
const dateSince = new Date(millisecondsFrom);
|
||||
const tsSince = dateToTs(dateSince);
|
||||
this.creationDateSince?.setValue(dateSince);
|
||||
const millisecondsUntil = filters.creationDateUntil;
|
||||
const dateUntil = new Date(millisecondsUntil);
|
||||
const tsUntil = dateToTs(dateUntil);
|
||||
this.creationDateUntil?.setValue(dateUntil);
|
||||
const range = new ListEventsRequest.creation_date_range();
|
||||
range.setSince(tsSince);
|
||||
range.setUntil(tsUntil);
|
||||
this.request.setRange(range);
|
||||
this.creationDateFilterType?.setValue(CreationDateFilterType.RANGE);
|
||||
}
|
||||
if (filters.aggregateTypesList && filters.aggregateTypesList.length) {
|
||||
const values = this.aggregateTypes.filter((agg) => filters.aggregateTypesList.includes(agg.type));
|
||||
@ -146,6 +174,7 @@ export class FilterEventsComponent implements OnInit {
|
||||
|
||||
public reset(): void {
|
||||
this.form.reset();
|
||||
this.form.setValue(this.initialValues);
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
@ -252,11 +281,28 @@ export class FilterEventsComponent implements OnInit {
|
||||
constructRequest.setAsc(formValues.isAsc);
|
||||
filterObject.isAsc = formValues.isAsc;
|
||||
}
|
||||
if (formValues.creationDateFilterSet && formValues.creationDate) {
|
||||
const date = new Date(formValues.creationDate);
|
||||
const ts = dateToTs(date);
|
||||
constructRequest.setCreationDate(ts);
|
||||
filterObject.creationDate = date.getTime();
|
||||
if (formValues.creationDateFilterType === CreationDateFilterType.FROM) {
|
||||
const dateFrom = new Date(formValues.creationDateFrom);
|
||||
const tsFrom = dateToTs(dateFrom);
|
||||
constructRequest.setFrom(tsFrom);
|
||||
constructRequest.clearRange();
|
||||
filterObject.creationDateFrom = dateFrom.getTime();
|
||||
filterObject.creationDateSince = undefined;
|
||||
filterObject.creationDateUntil = undefined;
|
||||
}
|
||||
if (formValues.creationDateFilterType === CreationDateFilterType.RANGE) {
|
||||
const range = new ListEventsRequest.creation_date_range();
|
||||
const dateSince = new Date(formValues.creationDateSince);
|
||||
const tsSince = dateToTs(dateSince);
|
||||
range.setSince(tsSince);
|
||||
filterObject.creationDateSince = dateSince.getTime();
|
||||
const dateUntil = new Date(formValues.creationDateUntil);
|
||||
const tsUntil = dateToTs(dateUntil);
|
||||
range.setUntil(tsUntil);
|
||||
filterObject.creationDateUntil = dateUntil.getTime();
|
||||
constructRequest.setRange(range);
|
||||
constructRequest.clearFrom();
|
||||
filterObject.creationDateFrom = undefined;
|
||||
}
|
||||
|
||||
this.requestChanged.emit(constructRequest);
|
||||
@ -265,7 +311,7 @@ export class FilterEventsComponent implements OnInit {
|
||||
this.router.navigate([], {
|
||||
relativeTo: this.route,
|
||||
queryParams: {
|
||||
['filter']: JSON.stringify(filterObject),
|
||||
['filter']: encodeURIComponent(JSON.stringify(filterObject)),
|
||||
},
|
||||
replaceUrl: true,
|
||||
queryParamsHandling: 'merge',
|
||||
@ -304,12 +350,32 @@ export class FilterEventsComponent implements OnInit {
|
||||
return this.form.get('sequenceFilterSet');
|
||||
}
|
||||
|
||||
public get creationDate(): AbstractControl | null {
|
||||
return this.form.get('creationDate');
|
||||
public get creationDateFilterType(): AbstractControl | null {
|
||||
return this.form.get('creationDateFilterType');
|
||||
}
|
||||
|
||||
public get creationDateFilterSet(): AbstractControl | null {
|
||||
return this.form.get('creationDateFilterSet');
|
||||
public get creationDateFrom(): AbstractControl | null {
|
||||
return this.form.get('creationDateFrom');
|
||||
}
|
||||
|
||||
public set creationDateFrom(event: EventTarget | null) {
|
||||
this.setDate(this.creationDateFrom!, event);
|
||||
}
|
||||
|
||||
public get creationDateSince(): AbstractControl | null {
|
||||
return this.form.get('creationDateSince');
|
||||
}
|
||||
|
||||
public set creationDateSince(event: EventTarget | null) {
|
||||
this.setDate(this.creationDateSince!, event);
|
||||
}
|
||||
|
||||
public get creationDateUntil(): AbstractControl | null {
|
||||
return this.form.get('creationDateUntil');
|
||||
}
|
||||
|
||||
public set creationDateUntil(event: EventTarget | null) {
|
||||
this.setDate(this.creationDateUntil!, event);
|
||||
}
|
||||
|
||||
public get resourceOwnerFilterSet(): AbstractControl | null {
|
||||
@ -341,9 +407,6 @@ export class FilterEventsComponent implements OnInit {
|
||||
if (this.userFilterSet?.value && this.editorUserId?.value) {
|
||||
++count;
|
||||
}
|
||||
if (this.creationDateFilterSet?.value && this.creationDate?.value) {
|
||||
++count;
|
||||
}
|
||||
if (this.aggregateFilterSet?.value && this.aggregateId?.value) {
|
||||
++count;
|
||||
}
|
||||
@ -361,4 +424,11 @@ export class FilterEventsComponent implements OnInit {
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private setDate(ctrl: AbstractControl<Date>, event: EventTarget | null): void {
|
||||
if (!(event instanceof HTMLInputElement)) {
|
||||
throw new Error('wrong target');
|
||||
}
|
||||
ctrl.setValue(new Date(event.value || ''));
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { ActionKeysModule } from '../action-keys/action-keys.module';
|
||||
import { InputModule } from '../input/input.module';
|
||||
import { FilterEventsComponent } from './filter-events.component';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
|
||||
@NgModule({
|
||||
declarations: [FilterEventsComponent],
|
||||
@ -28,6 +30,8 @@ import { FilterEventsComponent } from './filter-events.component';
|
||||
MatCheckboxModule,
|
||||
MatSelectModule,
|
||||
ActionKeysModule,
|
||||
MatInputModule,
|
||||
MatRadioModule,
|
||||
],
|
||||
exports: [FilterEventsComponent],
|
||||
})
|
||||
|
@ -1,27 +0,0 @@
|
||||
<h2>{{ 'SETTING.DEFAULTLANGUAGE' | translate }}</h2>
|
||||
|
||||
<div class="spinner-wr">
|
||||
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<cnsl-form-field class="default-language" label="Default Language" required="true">
|
||||
<cnsl-label>{{ 'SETTING.DEFAULTLANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="defaultLanguage" [disabled]="(['iam.policy.write'] | hasRole | async) === false">
|
||||
<mat-option *ngFor="let lang of defaultLanguageOptions" [value]="lang">
|
||||
{{ lang }} - {{ 'SETTING.LANGUAGE.' + lang | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="general-btn-container">
|
||||
<button
|
||||
class="save-button"
|
||||
(click)="savePolicy()"
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
[disabled]="(['iam.policy.write'] | hasRole | async) === false"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
.spinner-wr {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.default-language {
|
||||
max-width: 400px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.general-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: 1rem;
|
||||
|
||||
.save-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { SetDefaultLanguageResponse } from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-general-settings',
|
||||
templateUrl: './general-settings.component.html',
|
||||
styleUrls: ['./general-settings.component.scss'],
|
||||
})
|
||||
export class GeneralSettingsComponent implements OnInit {
|
||||
public defaultLanguage: string = '';
|
||||
public defaultLanguageOptions: string[] = [];
|
||||
|
||||
public loading: boolean = false;
|
||||
constructor(
|
||||
private service: AdminService,
|
||||
private toast: ToastService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
private fetchData(): void {
|
||||
this.service.getDefaultLanguage().then((langResp) => {
|
||||
this.defaultLanguage = langResp.language;
|
||||
});
|
||||
this.service.getSupportedLanguages().then((supportedResp) => {
|
||||
this.defaultLanguageOptions = supportedResp.languagesList;
|
||||
});
|
||||
}
|
||||
|
||||
private updateData(): Promise<SetDefaultLanguageResponse.AsObject> {
|
||||
return (this.service as AdminService).setDefaultLanguage(this.defaultLanguage);
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
const prom = this.updateData();
|
||||
this.loading = true;
|
||||
if (prom) {
|
||||
prom
|
||||
.then(() => {
|
||||
this.toast.showInfo('POLICY.LOGIN_POLICY.SAVED', true);
|
||||
this.loading = false;
|
||||
setTimeout(() => {
|
||||
this.fetchData();
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.loading = false;
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { FormFieldModule } from '../../form-field/form-field.module';
|
||||
import { GeneralSettingsComponent } from './general-settings.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [GeneralSettingsComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardModule,
|
||||
FormsModule,
|
||||
MatButtonModule,
|
||||
FormFieldModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatSelectModule,
|
||||
HasRolePipeModule,
|
||||
TranslateModule,
|
||||
],
|
||||
exports: [GeneralSettingsComponent],
|
||||
})
|
||||
export class GeneralSettingsModule {}
|
@ -0,0 +1,135 @@
|
||||
<h2>{{ 'SETTING.LANGUAGES.TITLE' | translate }}</h2>
|
||||
|
||||
<div class="spinner-wr">
|
||||
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form class="languages-container-wrapper">
|
||||
<div class="languages-container">
|
||||
<div
|
||||
class="languages-list"
|
||||
cdkDropList
|
||||
id="allowed"
|
||||
[cdkDropListConnectedTo]="['notallowed']"
|
||||
(cdkDropListDropped)="drop($event)"
|
||||
[cdkDropListData]="(localState$ | async)!.allowed"
|
||||
>
|
||||
<div class="languages-top-row">
|
||||
<span class="label">{{ 'SETTING.LANGUAGES.ALLOWED' | translate }}</span>
|
||||
<button
|
||||
class="list-button"
|
||||
[disabled]="(canWriteRestrictions$ | async) === false"
|
||||
(click)="allowAll()"
|
||||
mat-stroked-button
|
||||
>
|
||||
<div class="cnsl-action-button">
|
||||
<i class="las la-object-group"></i><span>{{ 'SETTING.LANGUAGES.ALLOW_ALL' | translate }}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="languages-drop-target">
|
||||
<div
|
||||
class="card languages-box"
|
||||
*ngFor="let lang of (localState$ | async)!.allowed; index as i"
|
||||
[cdkDragData]="lang"
|
||||
cdkDrag
|
||||
[cdkDragDisabled]="(canWriteRestrictions$ | async) === false"
|
||||
mat-list-item
|
||||
>
|
||||
<span class="index">{{ i + 1 }}</span>
|
||||
<span class="locale">{{ lang }}</span>
|
||||
<span class="lang">{{ 'SETTING.LANGUAGES.OPTIONS.' + lang | translate }} </span>
|
||||
<span *ngIf="lang === (defaultLang$ | async)" class="state orgdefaultlabel">{{
|
||||
'SETTING.LANGUAGES.DEFAULT' | translate
|
||||
}}</span>
|
||||
|
||||
<button
|
||||
(click)="$event.stopPropagation()"
|
||||
*ngIf="lang !== (defaultLang$ | async) && (isRemotelyAllowed$(lang) | async) === true"
|
||||
mat-icon-button
|
||||
class="more-button"
|
||||
[matMenuTriggerFor]="actions"
|
||||
data-e2e="table-actions-button"
|
||||
>
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #actions="matMenu" xPosition="before" class="language-actions-menu">
|
||||
<button
|
||||
menuActions
|
||||
mat-menu-item
|
||||
(click)="setDefaultLang(lang)"
|
||||
[disabled]="(canWriteDefaultLanguage$ | async) === false"
|
||||
>
|
||||
{{ 'SETTING.LANGUAGES.SETASDEFAULT' | translate }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="languages-container">
|
||||
<div
|
||||
class="languages-list"
|
||||
cdkDropList
|
||||
id="notallowed"
|
||||
[cdkDropListConnectedTo]="['allowed']"
|
||||
(cdkDropListDropped)="drop($event)"
|
||||
[cdkDropListData]="(localState$ | async)!.notAllowed"
|
||||
[cdkDropListEnterPredicate]="defaultLangPredicate"
|
||||
cdkDropListSortingDisabled
|
||||
>
|
||||
<div class="languages-top-row">
|
||||
<span class="label">{{ 'SETTING.LANGUAGES.NOT_ALLOWED' | translate }}</span>
|
||||
<button
|
||||
class="list-button"
|
||||
[disabled]="(canWriteRestrictions$ | async) === false"
|
||||
(click)="disallowAll()"
|
||||
mat-stroked-button
|
||||
>
|
||||
<div class="cnsl-action-button">
|
||||
<i class="las la-object-group"></i><span>{{ 'SETTING.LANGUAGES.DISALLOW_ALL' | translate }}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="languages-drop-target">
|
||||
<div
|
||||
class="card languages-box"
|
||||
*ngFor="let lang of (localState$ | async)!.notAllowed"
|
||||
[cdkDragData]="lang"
|
||||
cdkDrag
|
||||
[cdkDragDisabled]="(canWriteRestrictions$ | async) === false"
|
||||
mat-list-item
|
||||
>
|
||||
<span class="locale">{{ lang }}</span>
|
||||
<span class="lang">{{ 'SETTING.LANGUAGES.OPTIONS.' + lang | translate }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="general-btn-container">
|
||||
<button
|
||||
class="reset-button"
|
||||
[disabled]="(canWriteRestrictions$ | async) === false"
|
||||
(click)="discard()"
|
||||
color="message-text-warn"
|
||||
mat-stroked-button
|
||||
>
|
||||
<div class="cnsl-action-button">
|
||||
<i class="las la-history"></i><span>{{ 'ACTIONS.UNSAVED.DIALOG.DISCARD' | translate }}</span>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
class="save-button"
|
||||
color="primary"
|
||||
type="submit"
|
||||
(click)="submit()"
|
||||
mat-raised-button
|
||||
[disabled]="(canWriteRestrictions$ | async) === false"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -0,0 +1,112 @@
|
||||
.languages-container-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
column-gap: 2rem;
|
||||
|
||||
@media only screen and (max-width: 700px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.languages-container {
|
||||
display: inline-block;
|
||||
max-width: 400px;
|
||||
vertical-align: top;
|
||||
width: 100%;
|
||||
|
||||
.spinner-wr {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.default-language {
|
||||
max-width: 400px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.general-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: 1rem;
|
||||
|
||||
.save-button {
|
||||
display: block;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.languages-list {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
height: 100%;
|
||||
|
||||
.languages-top-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
|
||||
.label {
|
||||
margin-right: 1rem;
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.list-button {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.languages-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 0.5rem 0.5rem 2rem;
|
||||
height: 56px;
|
||||
cursor: move;
|
||||
margin: 2px 0;
|
||||
|
||||
.index {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
opacity: 0.5;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.locale {
|
||||
width: 35px;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.lang {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
[hoveractions] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.more-button {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
[hoveractions] {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.defaultlanglabel {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GeneralSettingsComponent } from './general-settings.component';
|
||||
import { LanguageSettingsComponent } from './language-settings.component';
|
||||
|
||||
describe('GeneralSettingsComponent', () => {
|
||||
let component: GeneralSettingsComponent;
|
||||
let fixture: ComponentFixture<GeneralSettingsComponent>;
|
||||
describe('LanguageSettingsComponent', () => {
|
||||
let component: LanguageSettingsComponent;
|
||||
let fixture: ComponentFixture<LanguageSettingsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [GeneralSettingsComponent],
|
||||
declarations: [LanguageSettingsComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(GeneralSettingsComponent);
|
||||
fixture = TestBed.createComponent(LanguageSettingsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
@ -0,0 +1,116 @@
|
||||
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { UntypedFormBuilder } from '@angular/forms';
|
||||
import { LanguagesService } from '../../../services/languages.service';
|
||||
import { BehaviorSubject, concat, forkJoin, from, Observable, of, Subject, switchMap, take, takeUntil } from 'rxjs';
|
||||
import { GrpcAuthService } from '../../../services/grpc-auth.service';
|
||||
import { CdkDrag, CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
interface State {
|
||||
allowed: string[];
|
||||
notAllowed: string[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-language-settings',
|
||||
templateUrl: './language-settings.component.html',
|
||||
styleUrls: ['./language-settings.component.scss'],
|
||||
})
|
||||
export class LanguageSettingsComponent {
|
||||
public canWriteRestrictions$: Observable<boolean> = this.authService.isAllowed(['iam.restrictions.write']);
|
||||
public canWriteDefaultLanguage$: Observable<boolean> = this.authService.isAllowed(['iam.write']);
|
||||
|
||||
public localState$ = new BehaviorSubject<State>({ allowed: [], notAllowed: [] });
|
||||
public remoteState$ = new BehaviorSubject<State>({ allowed: [], notAllowed: [] });
|
||||
public defaultLang$ = new BehaviorSubject<string>('');
|
||||
|
||||
public loading: boolean = false;
|
||||
constructor(
|
||||
private service: AdminService,
|
||||
private toast: ToastService,
|
||||
private langSvc: LanguagesService,
|
||||
private authService: GrpcAuthService,
|
||||
) {
|
||||
const sub = forkJoin([
|
||||
langSvc.allowed$.pipe(take(1)),
|
||||
langSvc.notAllowed$.pipe(take(1)),
|
||||
from(this.service.getDefaultLanguage()).pipe(take(1)),
|
||||
]).subscribe({
|
||||
next: ([allowed, notAllowed, { language: defaultLang }]) => {
|
||||
this.defaultLang$.next(defaultLang);
|
||||
this.remoteState$.next({ notAllowed: [...notAllowed], ...{ allowed: [...allowed] } });
|
||||
this.localState$.next({ notAllowed: [...notAllowed], ...{ allowed: [...allowed] } });
|
||||
},
|
||||
error: this.toast.showError,
|
||||
complete: () => {
|
||||
sub.unsubscribe();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
drop(event: CdkDragDrop<string[]>) {
|
||||
if (event.previousContainer === event.container) {
|
||||
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
|
||||
} else {
|
||||
transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public defaultLangPredicate = (lang: CdkDrag<string>) => {
|
||||
return !!lang?.data && lang.data !== this.defaultLang$.value;
|
||||
};
|
||||
|
||||
public isRemotelyAllowed$(lang: string): Observable<boolean> {
|
||||
return this.remoteState$.pipe(map(({ allowed }) => allowed.includes(lang)));
|
||||
}
|
||||
|
||||
public allowAll(): void {
|
||||
this.localState$.next({ allowed: [...this.allLocalLangs()], notAllowed: [] });
|
||||
}
|
||||
|
||||
public disallowAll(): void {
|
||||
const disallowed = this.allLocalLangs().filter((lang) => lang !== this.defaultLang$.value);
|
||||
this.localState$.next({ allowed: [this.defaultLang$.value], notAllowed: disallowed });
|
||||
}
|
||||
|
||||
public submit(): void {
|
||||
const { allowed, notAllowed } = this.localState$.value;
|
||||
const sub = from(this.service.setRestrictions(undefined, allowed)).subscribe({
|
||||
next: () => {
|
||||
this.remoteState$.next({
|
||||
allowed: [...allowed],
|
||||
notAllowed: [...notAllowed],
|
||||
});
|
||||
this.langSvc.newAllowed(allowed);
|
||||
this.toast.showInfo('SETTING.LANGUAGES.ALLOWED_SAVED', true);
|
||||
},
|
||||
error: this.toast.showError,
|
||||
complete: () => {
|
||||
sub.unsubscribe();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public discard(): void {
|
||||
this.localState$.next(this.remoteState$.value);
|
||||
}
|
||||
|
||||
public setDefaultLang(lang: string): void {
|
||||
const sub = from(this.service.setDefaultLanguage(lang)).subscribe({
|
||||
next: () => {
|
||||
this.defaultLang$.next(lang);
|
||||
this.toast.showInfo('SETTING.LANGUAGES.DEFAULT_SAVED', true);
|
||||
},
|
||||
error: this.toast.showError,
|
||||
complete: () => {
|
||||
sub.unsubscribe();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private allLocalLangs(): string[] {
|
||||
return [...this.localState$.value.allowed, ...this.localState$.value.notAllowed];
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { FormFieldModule } from '../../form-field/form-field.module';
|
||||
import { LanguageSettingsComponent } from './language-settings.component';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TableActionsModule } from '../../table-actions/table-actions.module';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
@NgModule({
|
||||
declarations: [LanguageSettingsComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonModule,
|
||||
MatSelectModule,
|
||||
FormFieldModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatSelectModule,
|
||||
HasRolePipeModule,
|
||||
TranslateModule,
|
||||
MatListModule,
|
||||
DragDropModule,
|
||||
MatRadioModule,
|
||||
MatTooltipModule,
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
],
|
||||
exports: [LanguageSettingsComponent],
|
||||
})
|
||||
export class LanguageSettingsModule {}
|
@ -242,14 +242,20 @@
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.ALLOWREGISTER' | translate }}
|
||||
{{ 'POLICY.DATA.ALLOWREGISTERUSERS' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div class="login-policy-row">
|
||||
<mat-checkbox
|
||||
class="login-policy-toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="allowOrgRegistration"
|
||||
*ngIf="serviceType === PolicyComponentServiceType.ADMIN"
|
||||
[disabled]="(['iam.restrictions.write'] | hasRole | async) === false"
|
||||
>
|
||||
{{ 'POLICY.DATA.ALLOWREGISTERORGS' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<!-- <ng-template #regInfo>
|
||||
<cnsl-info-section class="info">
|
||||
{{ 'POLICY.DATA.ALLOWREGISTER_DESC' | translate }}
|
||||
</cnsl-info-section>
|
||||
</ng-template> -->
|
||||
</div>
|
||||
<div class="login-policy-row">
|
||||
<mat-checkbox
|
||||
@ -428,6 +434,7 @@
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
[disabled]="
|
||||
(['iam.restrictions.write'] | hasRole | async) === false &&
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Component, Injector, Input, OnInit, Type } from '@angular/core';
|
||||
import { Component, Injector, Input, OnDestroy, OnInit, Type } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
|
||||
import { take } from 'rxjs';
|
||||
import { firstValueFrom, forkJoin, from, Observable, of, Subject, take } from 'rxjs';
|
||||
import {
|
||||
GetLoginPolicyResponse as AdminGetLoginPolicyResponse,
|
||||
UpdateLoginPolicyRequest,
|
||||
@ -24,19 +24,21 @@ import { InfoSectionType } from '../../info-section/info-section.component';
|
||||
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
|
||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
import { LoginMethodComponentType } from './factor-table/factor-table.component';
|
||||
import { catchError, map, takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-login-policy',
|
||||
templateUrl: './login-policy.component.html',
|
||||
styleUrls: ['./login-policy.component.scss'],
|
||||
})
|
||||
export class LoginPolicyComponent implements OnInit {
|
||||
export class LoginPolicyComponent implements OnInit, OnDestroy {
|
||||
public LoginMethodComponentType: any = LoginMethodComponentType;
|
||||
public passwordlessTypes: Array<PasswordlessType> = [
|
||||
PasswordlessType.PASSWORDLESS_TYPE_NOT_ALLOWED,
|
||||
PasswordlessType.PASSWORDLESS_TYPE_ALLOWED,
|
||||
];
|
||||
public loginData?: LoginPolicy.AsObject;
|
||||
public allowOrgRegistration: boolean = false;
|
||||
|
||||
public service!: ManagementService | AdminService;
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
@ -52,6 +54,8 @@ export class LoginPolicyComponent implements OnInit {
|
||||
secondFactorCheckLifetime: [{ disabled: true }, [requiredValidator]],
|
||||
multiFactorCheckLifetime: [{ disabled: true }, [requiredValidator]],
|
||||
});
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
@ -60,43 +64,59 @@ export class LoginPolicyComponent implements OnInit {
|
||||
private dialog: MatDialog,
|
||||
) {}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
public fetchData(): void {
|
||||
this.getData()
|
||||
.then((resp) => {
|
||||
if (resp.policy) {
|
||||
this.loginData = resp.policy;
|
||||
this.loading = false;
|
||||
const data$ = forkJoin([
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? from((this.service as AdminService).getRestrictions()).pipe(
|
||||
map(({ disallowPublicOrgRegistration }) => disallowPublicOrgRegistration),
|
||||
)
|
||||
: of(true),
|
||||
from(this.getData()),
|
||||
]);
|
||||
|
||||
this.passwordCheckLifetime?.setValue(
|
||||
this.loginData.passwordCheckLifetime?.seconds ? this.loginData.passwordCheckLifetime?.seconds / 60 / 60 : 0,
|
||||
);
|
||||
|
||||
this.externalLoginCheckLifetime?.setValue(
|
||||
this.loginData.externalLoginCheckLifetime?.seconds
|
||||
? this.loginData.externalLoginCheckLifetime?.seconds / 60 / 60
|
||||
: 0,
|
||||
);
|
||||
|
||||
this.mfaInitSkipLifetime?.setValue(
|
||||
this.loginData.mfaInitSkipLifetime?.seconds ? this.loginData.mfaInitSkipLifetime?.seconds / 60 / 60 : 0,
|
||||
);
|
||||
|
||||
this.secondFactorCheckLifetime?.setValue(
|
||||
this.loginData.secondFactorCheckLifetime?.seconds
|
||||
? this.loginData.secondFactorCheckLifetime?.seconds / 60 / 60
|
||||
: 0,
|
||||
);
|
||||
|
||||
this.multiFactorCheckLifetime?.setValue(
|
||||
this.loginData.multiFactorCheckLifetime?.seconds
|
||||
? this.loginData.multiFactorCheckLifetime?.seconds / 60 / 60
|
||||
: 0,
|
||||
);
|
||||
const sub = data$.pipe(takeUntil(this.destroy$)).subscribe({
|
||||
next: ([disallowPublicOrgRegistration, resp]) => {
|
||||
this.allowOrgRegistration = !disallowPublicOrgRegistration;
|
||||
if (!resp.policy) {
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
this.loginData = resp.policy;
|
||||
this.loading = false;
|
||||
|
||||
this.passwordCheckLifetime?.setValue(
|
||||
this.loginData.passwordCheckLifetime?.seconds ? this.loginData.passwordCheckLifetime?.seconds / 60 / 60 : 0,
|
||||
);
|
||||
|
||||
this.externalLoginCheckLifetime?.setValue(
|
||||
this.loginData.externalLoginCheckLifetime?.seconds
|
||||
? this.loginData.externalLoginCheckLifetime?.seconds / 60 / 60
|
||||
: 0,
|
||||
);
|
||||
|
||||
this.mfaInitSkipLifetime?.setValue(
|
||||
this.loginData.mfaInitSkipLifetime?.seconds ? this.loginData.mfaInitSkipLifetime?.seconds / 60 / 60 : 0,
|
||||
);
|
||||
|
||||
this.secondFactorCheckLifetime?.setValue(
|
||||
this.loginData.secondFactorCheckLifetime?.seconds
|
||||
? this.loginData.secondFactorCheckLifetime?.seconds / 60 / 60
|
||||
: 0,
|
||||
);
|
||||
|
||||
this.multiFactorCheckLifetime?.setValue(
|
||||
this.loginData.multiFactorCheckLifetime?.seconds ? this.loginData.multiFactorCheckLifetime?.seconds / 60 / 60 : 0,
|
||||
);
|
||||
},
|
||||
error: this.toast.showError,
|
||||
complete: () => {
|
||||
sub.unsubscribe();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
@ -142,7 +162,9 @@ export class LoginPolicyComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private async updateData(): Promise<UpdateLoginPolicyResponse.AsObject> {
|
||||
private async updateData(): Promise<any> {
|
||||
const calls: Observable<any>[] = [];
|
||||
|
||||
if (this.loginData) {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
@ -179,7 +201,8 @@ export class LoginPolicyComponent implements OnInit {
|
||||
mgmtreq.setIgnoreUnknownUsernames(this.loginData.ignoreUnknownUsernames);
|
||||
mgmtreq.setDefaultRedirectUri(this.loginData.defaultRedirectUri);
|
||||
|
||||
return (this.service as ManagementService).addCustomLoginPolicy(mgmtreq);
|
||||
calls.push(from((this.service as ManagementService).addCustomLoginPolicy(mgmtreq)));
|
||||
break;
|
||||
} else {
|
||||
const mgmtreq = new UpdateCustomLoginPolicyRequest();
|
||||
mgmtreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
|
||||
@ -211,7 +234,8 @@ export class LoginPolicyComponent implements OnInit {
|
||||
mgmtreq.setIgnoreUnknownUsernames(this.loginData.ignoreUnknownUsernames);
|
||||
mgmtreq.setDefaultRedirectUri(this.loginData.defaultRedirectUri);
|
||||
|
||||
return (this.service as ManagementService).updateCustomLoginPolicy(mgmtreq);
|
||||
calls.push(from((this.service as ManagementService).updateCustomLoginPolicy(mgmtreq)));
|
||||
break;
|
||||
}
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
const adminreq = new UpdateLoginPolicyRequest();
|
||||
@ -243,11 +267,21 @@ export class LoginPolicyComponent implements OnInit {
|
||||
adminreq.setIgnoreUnknownUsernames(this.loginData.ignoreUnknownUsernames);
|
||||
adminreq.setDefaultRedirectUri(this.loginData.defaultRedirectUri);
|
||||
|
||||
return (this.service as AdminService).updateLoginPolicy(adminreq);
|
||||
calls.push(from((this.service as AdminService).setRestrictions(!this.allowOrgRegistration)));
|
||||
calls.push(from((this.service as AdminService).updateLoginPolicy(adminreq)));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return Promise.reject();
|
||||
calls.push(from(Promise.reject()));
|
||||
}
|
||||
return firstValueFrom(
|
||||
forkJoin(calls).pipe(
|
||||
catchError((error, caught) => {
|
||||
// We just ignore the policy not changed error!
|
||||
return (error as { message: string }).message.includes('INSTANCE-5M9vdd') ? of(true) : caught;
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
|
@ -1,5 +1,8 @@
|
||||
<h2>{{ 'POLICY.LOGIN_TEXTS.TITLE' | translate }}</h2>
|
||||
<p class="cnsl-secondary-text">{{ 'POLICY.LOGIN_TEXTS.DESCRIPTION' | translate }}</p>
|
||||
<cnsl-info-section class="locked" *ngIf="langSvc.isNotAllowed(language) | async" [type]="InfoSectionType.WARN">
|
||||
{{ 'POLICY.LOGIN_TEXTS.ACTIVE_LANGUAGE_NOT_ALLOWED' | translate }}</cnsl-info-section
|
||||
>
|
||||
|
||||
<div *ngIf="loading" class="spinner-wr">
|
||||
<mat-spinner diameter="30" color="primary"></mat-spinner>
|
||||
@ -24,7 +27,7 @@
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<form *ngIf="form" class="top-actions" [formGroup]="form">
|
||||
<form *ngIf="allowed$ | async" class="top-actions" [formGroup]="form">
|
||||
<cnsl-form-field class="keys">
|
||||
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.KEYNAME' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="currentSubMap" name="currentSubMap">
|
||||
@ -35,18 +38,30 @@
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="language">
|
||||
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.LOCALE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="locale" name="locale">
|
||||
<mat-option *ngFor="let loc of LOCALES" [value]="loc">
|
||||
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.LANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="language" name="language">
|
||||
<mat-option *ngFor="let lang of allowed$ | async" [value]="lang">
|
||||
<div class="centerline">
|
||||
<span
|
||||
>{{ loc }}
|
||||
>{{ lang }}
|
||||
<span class="lighter cnsl-secondary-text"
|
||||
>| {{ 'POLICY.LOGIN_TEXTS.LOCALES.' + loc | translate }}</span
|
||||
>| {{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
|
||||
></span
|
||||
>
|
||||
</div>
|
||||
</mat-option>
|
||||
<mat-optgroup [label]="'POLICY.LOGIN_TEXTS.LANGUAGES_NOT_ALLOWED' | translate" *ngIf="langSvc.restricted$ | async">
|
||||
<mat-option *ngFor="let lang of langSvc.notAllowed$ | async" [value]="lang">
|
||||
<div class="centerline">
|
||||
<span
|
||||
>{{ lang }}
|
||||
<span class="lighter cnsl-secondary-text"
|
||||
>| {{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
|
||||
></span
|
||||
>
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-optgroup>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</form>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Component, Injector, Input, OnDestroy, OnInit, Type } from '@angular/core';
|
||||
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { FormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
||||
import { BehaviorSubject, from, interval, Observable, of, Subject, Subscription } from 'rxjs';
|
||||
import { BehaviorSubject, from, interval, Observable, of, Subject, Subscription, switchMap, take, tap } from 'rxjs';
|
||||
import { map, pairwise, startWith, takeUntil } from 'rxjs/operators';
|
||||
import {
|
||||
GetCustomLoginTextsRequest as AdminGetCustomLoginTextsRequest,
|
||||
@ -19,11 +19,11 @@ 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 { supportedLanguages } from 'src/app/utils/language';
|
||||
import { InfoSectionType } from '../../info-section/info-section.component';
|
||||
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
|
||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
import { mapRequestValues } from './helper';
|
||||
import { LanguagesService } from '../../../services/languages.service';
|
||||
|
||||
const MIN_INTERVAL_SECONDS = 10; // if the difference of a newer version to the current exceeds this time, a refresh button is shown.
|
||||
|
||||
@ -110,7 +110,6 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
@Input() public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
|
||||
public KeyNamesArray: string[] = KeyNamesArray;
|
||||
public LOCALES: string[] = supportedLanguages;
|
||||
|
||||
private sub: Subscription = new Subscription();
|
||||
|
||||
@ -119,9 +118,15 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
public destroy$: Subject<void> = new Subject();
|
||||
public InfoSectionType: any = InfoSectionType;
|
||||
public form: UntypedFormGroup = new UntypedFormGroup({
|
||||
currentSubMap: new UntypedFormControl('emailVerificationDoneText'),
|
||||
locale: new UntypedFormControl('en'),
|
||||
currentSubMap: new FormControl<string>('emailVerificationDoneText'),
|
||||
language: new FormControl<string>('en'),
|
||||
});
|
||||
public allowed$: Observable<string[]> = this.langSvc.allowed$.pipe(
|
||||
take(1),
|
||||
tap(([firstAllowed]) => {
|
||||
this.form.get('language')?.setValue(firstAllowed);
|
||||
}),
|
||||
);
|
||||
|
||||
public isDefault: boolean = false;
|
||||
|
||||
@ -137,9 +142,10 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
private injector: Injector,
|
||||
private dialog: MatDialog,
|
||||
private toast: ToastService,
|
||||
public langSvc: LanguagesService,
|
||||
) {
|
||||
this.form.valueChanges
|
||||
.pipe(startWith({ currentSubMap: 'emailVerificationDoneText', locale: 'en' }), pairwise(), takeUntil(this.destroy$))
|
||||
.pipe(startWith({ currentSubMap: 'emailVerificationDoneText', language: 'en' }), pairwise(), takeUntil(this.destroy$))
|
||||
.subscribe((pair) => {
|
||||
this.checkForUnsaved(pair[0].currentSubMap).then((wantsToSave) => {
|
||||
if (wantsToSave) {
|
||||
@ -162,21 +168,9 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
|
||||
this.service.getSupportedLanguages().then((lang) => {
|
||||
this.LOCALES = lang.languagesList;
|
||||
});
|
||||
|
||||
this.loadData();
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
|
||||
this.service.getSupportedLanguages().then((lang) => {
|
||||
this.LOCALES = lang.languagesList;
|
||||
});
|
||||
|
||||
this.loadData();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -215,10 +209,10 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
public async loadData(): Promise<any> {
|
||||
this.loading = true;
|
||||
const reqDefaultInit = REQUESTMAP[this.serviceType].getDefault;
|
||||
reqDefaultInit.setLanguage(this.locale);
|
||||
reqDefaultInit.setLanguage(this.language);
|
||||
this.getDefaultInitMessageTextMap$ = from(this.getDefaultValues(reqDefaultInit)).pipe(map((m) => m[this.currentSubMap]));
|
||||
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType].get.setLanguage(this.locale);
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType].get.setLanguage(this.language);
|
||||
return this.getCurrentValues(reqCustomInit)
|
||||
.then((policy) => {
|
||||
this.loading = false;
|
||||
@ -236,14 +230,14 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async patchSingleCurrentMap(): Promise<any> {
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType].get.setLanguage(this.locale);
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType].get.setLanguage(this.language);
|
||||
this.getCurrentValues(reqCustomInit).then((policy) => {
|
||||
this.getCustomInitMessageTextMap$.next(policy[this.currentSubMap]);
|
||||
});
|
||||
}
|
||||
|
||||
public checkForChanges(): void {
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType].get.setLanguage(this.locale);
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType].get.setLanguage(this.language);
|
||||
|
||||
(this.service as ManagementService).getCustomLoginTexts(reqCustomInit).then((policy) => {
|
||||
this.newerPolicyChangeDate = policy.customText?.details?.changeDate;
|
||||
@ -282,7 +276,7 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
this.totalCustomPolicy[this.currentSubMap] = values;
|
||||
|
||||
this.updateRequest = setFcn(this.totalCustomPolicy);
|
||||
this.updateRequest.setLanguage(this.locale);
|
||||
this.updateRequest.setLanguage(this.language);
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,7 +344,7 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
if (resp) {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
(this.service as ManagementService)
|
||||
.resetCustomLoginTextToDefault(this.locale)
|
||||
.resetCustomLoginTextToDefault(this.language)
|
||||
.then(() => {
|
||||
this.updateCurrentPolicyDate();
|
||||
this.isDefault = true;
|
||||
@ -363,7 +357,7 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
(this.service as AdminService)
|
||||
.resetCustomLoginTextToDefault(this.locale)
|
||||
.resetCustomLoginTextToDefault(this.language)
|
||||
.then(() => {
|
||||
this.updateCurrentPolicyDate();
|
||||
setTimeout(() => {
|
||||
@ -397,8 +391,12 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
public get locale(): string {
|
||||
return this.form.get('locale')?.value;
|
||||
public get language(): string {
|
||||
return this.form.get('language')?.value;
|
||||
}
|
||||
|
||||
public set language(lang: string) {
|
||||
this.form.get('language')?.setValue(lang);
|
||||
}
|
||||
|
||||
public get currentSubMap(): string {
|
||||
|
@ -1,70 +1,86 @@
|
||||
<h2>{{ 'POLICY.MESSAGE_TEXTS.TITLE' | translate }}</h2>
|
||||
<p class="cnsl-secondary-text">{{ 'POLICY.MESSAGE_TEXTS.DESCRIPTION' | translate }}</p>
|
||||
<cnsl-info-section class="locked" *ngIf="langSvc.isNotAllowed(language) | async" [type]="InfoSectionType.WARN">
|
||||
{{ 'POLICY.LOGIN_TEXTS.ACTIVE_LANGUAGE_NOT_ALLOWED' | translate }}</cnsl-info-section
|
||||
>
|
||||
|
||||
<div *ngIf="loading" class="spinner-wr">
|
||||
<mat-spinner diameter="30" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<div class="message-texts-top-actions">
|
||||
<cnsl-form-field class="type">
|
||||
<cnsl-label>{{ 'POLICY.MESSAGE_TEXTS.TYPE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="currentType" name="currentSubMap" (selectionChange)="changedCurrentType()">
|
||||
<mat-option *ngFor="let type of MESSAGETYPES | keyvalue" [value]="type.value">
|
||||
{{ 'POLICY.MESSAGE_TEXTS.TYPES.' + type.value | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<div *ngIf="allowed$ | async">
|
||||
<div class="message-texts-top-actions">
|
||||
<cnsl-form-field class="type">
|
||||
<cnsl-label>{{ 'POLICY.MESSAGE_TEXTS.TYPE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="currentType" name="currentSubMap" (selectionChange)="changedCurrentType()">
|
||||
<mat-option *ngFor="let type of MESSAGETYPES | keyvalue" [value]="type.value">
|
||||
{{ 'POLICY.MESSAGE_TEXTS.TYPES.' + type.value | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="language">
|
||||
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.LANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="language" (selectionChange)="changeLocale($event)" name="language">
|
||||
<mat-option *ngFor="let lang of langSvc.allowed$ | async" [value]="lang">
|
||||
<div class="centerline">
|
||||
<span
|
||||
>{{ lang }}
|
||||
<span class="lighter cnsl-secondary-text"
|
||||
>| {{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
|
||||
></span
|
||||
>
|
||||
</div>
|
||||
</mat-option>
|
||||
<mat-optgroup [label]="'POLICY.LOGIN_TEXTS.LANGUAGES_NOT_ALLOWED' | translate" *ngIf="langSvc.restricted$ | async">
|
||||
<mat-option *ngFor="let lang of langSvc.notAllowed$ | async" [value]="lang">
|
||||
<div class="centerline">
|
||||
<span
|
||||
>{{ lang }}
|
||||
<span class="lighter cnsl-secondary-text"
|
||||
>| {{ 'POLICY.LOGIN_TEXTS.LANGUAGES.' + lang | translate }}</span
|
||||
></span
|
||||
>
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-optgroup>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<cnsl-form-field class="language">
|
||||
<cnsl-label>{{ 'POLICY.LOGIN_TEXTS.LOCALE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="locale" name="locale" (selectionChange)="changeLocale($event)">
|
||||
<mat-option *ngFor="let loc of LOCALES" [value]="loc">
|
||||
<div class="centerline">
|
||||
<span
|
||||
>{{ loc }}
|
||||
<span class="lighter cnsl-secondary-text"
|
||||
>| {{ 'POLICY.LOGIN_TEXTS.LOCALES.' + loc | translate }}</span
|
||||
></span
|
||||
>
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="message-text-content">
|
||||
<cnsl-edit-text
|
||||
[chips]="chips[currentType]"
|
||||
[disabled]="(canWrite$ | async) === false"
|
||||
label="one"
|
||||
[default$]="getDefaultMessageTextMap$"
|
||||
[current$]="getCustomMessageTextMap$"
|
||||
(changedValues)="updateCurrentValues($event)"
|
||||
></cnsl-edit-text>
|
||||
</div>
|
||||
|
||||
<div class="message-text-content">
|
||||
<cnsl-edit-text
|
||||
[chips]="chips[currentType]"
|
||||
[disabled]="(canWrite$ | async) === false"
|
||||
label="one"
|
||||
[default$]="getDefaultMessageTextMap$"
|
||||
[current$]="getCustomMessageTextMap$"
|
||||
(changedValues)="updateCurrentValues($event)"
|
||||
></cnsl-edit-text>
|
||||
</div>
|
||||
|
||||
<div class="message-text-actions">
|
||||
<button
|
||||
class="reset-button"
|
||||
*ngIf="(getCustomMessageTextMap$ | async) && (getCustomMessageTextMap$ | async)?.['isDefault'] === false"
|
||||
[disabled]="(canWrite$ | async) === false"
|
||||
(click)="resetDefault()"
|
||||
color="message-text-warn"
|
||||
type="submit"
|
||||
mat-stroked-button
|
||||
>
|
||||
<div class="cnsl-action-button">
|
||||
<i class="las la-history"></i><span>{{ 'ACTIONS.RESETDEFAULT' | translate }}</span>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
class="save-button"
|
||||
[disabled]="!updateRequest || (canWrite$ | async) === false"
|
||||
(click)="saveCurrentMessage()"
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
<div class="message-text-actions">
|
||||
<button
|
||||
class="reset-button"
|
||||
*ngIf="(getCustomMessageTextMap$ | async) && (getCustomMessageTextMap$ | async)?.['isDefault'] === false"
|
||||
[disabled]="(canWrite$ | async) === false"
|
||||
(click)="resetDefault()"
|
||||
color="message-text-warn"
|
||||
type="submit"
|
||||
mat-stroked-button
|
||||
>
|
||||
<div class="cnsl-action-button">
|
||||
<i class="las la-history"></i><span>{{ 'ACTIONS.RESETDEFAULT' | translate }}</span>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
class="save-button"
|
||||
[disabled]="!updateRequest || (canWrite$ | async) === false"
|
||||
(click)="saveCurrentMessage()"
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component, Injector, Input, OnDestroy, OnInit, Type } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSelectChange } from '@angular/material/select';
|
||||
import { BehaviorSubject, from, Observable, of, Subscription } from 'rxjs';
|
||||
import { BehaviorSubject, from, Observable, of, Subscription, switchMap, take, tap } from 'rxjs';
|
||||
import {
|
||||
GetDefaultDomainClaimedMessageTextRequest as AdminGetDefaultDomainClaimedMessageTextRequest,
|
||||
GetDefaultInitMessageTextRequest as AdminGetDefaultInitMessageTextRequest,
|
||||
@ -57,10 +57,11 @@ 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 { supportedLanguages } from 'src/app/utils/language';
|
||||
import { InfoSectionType } from '../../info-section/info-section.component';
|
||||
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
|
||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { LanguagesService } from '../../../services/languages.service';
|
||||
|
||||
enum MESSAGETYPES {
|
||||
INIT = 'INIT',
|
||||
@ -537,8 +538,15 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
],
|
||||
};
|
||||
|
||||
public locale: string = 'en';
|
||||
public LOCALES: string[] = supportedLanguages;
|
||||
public language: string = 'en';
|
||||
public allowed$: Observable<string[]> = this.langSvc.allowed$.pipe(
|
||||
take(1),
|
||||
tap(([firstAllowed]) => {
|
||||
this.language = firstAllowed;
|
||||
this.loadData(this.currentType);
|
||||
}),
|
||||
);
|
||||
|
||||
private sub: Subscription = new Subscription();
|
||||
public canWrite$: Observable<boolean> = this.authService.isAllowed([
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
@ -553,23 +561,16 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private dialog: MatDialog,
|
||||
public langSvc: LanguagesService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
this.service.getSupportedLanguages().then((lang) => {
|
||||
this.LOCALES = lang.languagesList;
|
||||
});
|
||||
this.loadData(this.currentType);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
this.service.getSupportedLanguages().then((lang) => {
|
||||
this.LOCALES = lang.languagesList;
|
||||
});
|
||||
this.loadData(this.currentType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -623,7 +624,7 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public changeLocale(selection: MatSelectChange): void {
|
||||
this.locale = selection.value;
|
||||
this.language = selection.value;
|
||||
this.loadData(this.currentType);
|
||||
}
|
||||
|
||||
@ -631,11 +632,11 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const reqDefaultInit = REQUESTMAP[this.serviceType][type].getDefault;
|
||||
|
||||
reqDefaultInit.setLanguage(this.locale);
|
||||
reqDefaultInit.setLanguage(this.language);
|
||||
this.getDefaultMessageTextMap$ = from(this.getDefaultValues(type, reqDefaultInit));
|
||||
}
|
||||
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType][type].get.setLanguage(this.locale);
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType][type].get.setLanguage(this.language);
|
||||
this.loading = true;
|
||||
return this.getCurrentValues(type, reqCustomInit)
|
||||
?.then((data) => {
|
||||
@ -652,7 +653,7 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
const req = REQUESTMAP[this.serviceType][this.currentType].setFcn;
|
||||
const mappedValues = req(values);
|
||||
this.updateRequest = mappedValues;
|
||||
this.updateRequest.setLanguage(this.locale);
|
||||
this.updateRequest.setLanguage(this.language);
|
||||
}
|
||||
|
||||
public saveCurrentMessage(): any {
|
||||
@ -741,23 +742,23 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
|
||||
switch (this.currentType) {
|
||||
case MESSAGETYPES.INIT:
|
||||
return handler(this.service.resetCustomInitMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomInitMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.VERIFYPHONE:
|
||||
return handler(this.service.resetCustomVerifyPhoneMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomVerifyPhoneMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.VERIFYSMSOTP:
|
||||
return handler(this.service.resetCustomVerifySMSOTPMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomVerifySMSOTPMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.VERIFYEMAILOTP:
|
||||
return handler(this.service.resetCustomVerifyEmailOTPMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomVerifyEmailOTPMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.VERIFYEMAIL:
|
||||
return handler(this.service.resetCustomVerifyEmailMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomVerifyEmailMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.PASSWORDRESET:
|
||||
return handler(this.service.resetCustomPasswordResetMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomPasswordResetMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.DOMAINCLAIMED:
|
||||
return handler(this.service.resetCustomDomainClaimedMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomDomainClaimedMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.PASSWORDLESS:
|
||||
return handler(this.service.resetCustomPasswordlessRegistrationMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomPasswordlessRegistrationMessageTextToDefault(this.language));
|
||||
case MESSAGETYPES.PASSWORDCHANGE:
|
||||
return handler(this.service.resetCustomPasswordChangeMessageTextToDefault(this.locale));
|
||||
return handler(this.service.resetCustomPasswordChangeMessageTextToDefault(this.language));
|
||||
default:
|
||||
return Promise.reject();
|
||||
}
|
||||
|
@ -6,9 +6,6 @@
|
||||
[settingsList]="settingsList"
|
||||
queryParam="id"
|
||||
>
|
||||
<ng-container *ngIf="currentSetting === 'general' && serviceType === PolicyComponentServiceType.ADMIN">
|
||||
<cnsl-general-settings></cnsl-general-settings>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="currentSetting === 'complexity'">
|
||||
<cnsl-password-complexity-policy [serviceType]="serviceType"></cnsl-password-complexity-policy>
|
||||
</ng-container>
|
||||
@ -57,4 +54,7 @@
|
||||
<ng-container *ngIf="currentSetting === 'privacypolicy'">
|
||||
<cnsl-privacy-policy [serviceType]="serviceType"></cnsl-privacy-policy>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="currentSetting === 'languages' && serviceType === PolicyComponentServiceType.ADMIN">
|
||||
<cnsl-language-settings></cnsl-language-settings>
|
||||
</ng-container>
|
||||
</cnsl-sidenav>
|
||||
|
@ -7,7 +7,7 @@ import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.mod
|
||||
import { CardModule } from '../card/card.module';
|
||||
import DomainsModule from '../domains/domains.module';
|
||||
import { DomainPolicyModule } from '../policies/domain-policy/domain-policy.module';
|
||||
import { GeneralSettingsModule } from '../policies/general-settings/general-settings.module';
|
||||
import { LanguageSettingsModule } from '../policies/language-settings/language-settings.module';
|
||||
import { IdpSettingsModule } from '../policies/idp-settings/idp-settings.module';
|
||||
import { LoginPolicyModule } from '../policies/login-policy/login-policy.module';
|
||||
import { LoginTextsPolicyModule } from '../policies/login-texts/login-texts.module';
|
||||
@ -36,7 +36,7 @@ import { SettingsListComponent } from './settings-list.component';
|
||||
PasswordComplexityPolicyModule,
|
||||
PasswordLockoutPolicyModule,
|
||||
PrivateLabelingPolicyModule,
|
||||
GeneralSettingsModule,
|
||||
LanguageSettingsModule,
|
||||
NotificationPolicyModule,
|
||||
IdpSettingsModule,
|
||||
PrivacyPolicyModule,
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
|
||||
import { SidenavSetting } from '../sidenav/sidenav.component';
|
||||
|
||||
export const GENERAL: SidenavSetting = {
|
||||
id: 'general',
|
||||
i18nKey: 'SETTINGS.LIST.GENERAL',
|
||||
export const LANGUAGES: SidenavSetting = {
|
||||
id: 'languages',
|
||||
i18nKey: 'SETTINGS.LIST.LANGUAGES',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
|
@ -83,8 +83,8 @@ export class ActionTableComponent implements OnInit {
|
||||
this.mgmtService
|
||||
.deleteAction(action.id)
|
||||
.then(() => {
|
||||
this.selection.clear();
|
||||
this.toast.showInfo('FLOWS.DIALOG.DELETEACTION.DELETE_SUCCESS', true);
|
||||
|
||||
this.refreshPage();
|
||||
})
|
||||
.catch((error: any) => {
|
||||
|
@ -70,7 +70,7 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="sequence">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header [start]="'desc'" [disableClear]="true">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
{{ 'IAM.EVENTS.SEQUENCE' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let event">
|
||||
@ -81,10 +81,12 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="creationDate">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'IAM.EVENTS.CREATIONDATE' | translate }}</th>
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header [start]="'desc'" [disableClear]="true">
|
||||
{{ 'IAM.EVENTS.CREATIONDATE' | translate }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let event">
|
||||
<ng-container *ngIf="event | toobject as event">
|
||||
<span>{{ event?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
||||
<span>{{ event?.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm:ss' }}</span>
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
@ -176,13 +176,13 @@ export class EventsComponent implements OnDestroy {
|
||||
req.setEditorUserId(filterRequest.getEditorUserId());
|
||||
req.setResourceOwner(filterRequest.getResourceOwner());
|
||||
req.setSequence(filterRequest.getSequence());
|
||||
req.setCreationDate(filterRequest.getCreationDate());
|
||||
req.setRange(filterRequest.getRange());
|
||||
req.setFrom(filterRequest.getFrom());
|
||||
const isAsc: boolean = filterRequest.getAsc();
|
||||
req.setAsc(isAsc);
|
||||
if (this.sortAsc !== isAsc) {
|
||||
this.sort.sort({ id: 'sequence', start: isAsc ? 'asc' : 'desc', disableClear: true });
|
||||
this.sort.sort({ id: 'creationDate', start: isAsc ? 'asc' : 'desc', disableClear: true });
|
||||
}
|
||||
|
||||
this.loadEvents(req, true);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
BRANDING,
|
||||
COMPLEXITY,
|
||||
DOMAIN,
|
||||
GENERAL,
|
||||
LANGUAGES,
|
||||
IDP,
|
||||
LOCKOUT,
|
||||
LOGIN,
|
||||
@ -34,7 +34,6 @@ export class InstanceSettingsComponent implements OnInit, OnDestroy {
|
||||
public id: string = '';
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
public defaultSettingsList: SidenavSetting[] = [
|
||||
GENERAL,
|
||||
// notifications
|
||||
// { showWarn: true, ...NOTIFICATIONS },
|
||||
NOTIFICATIONS,
|
||||
@ -53,6 +52,7 @@ export class InstanceSettingsComponent implements OnInit, OnDestroy {
|
||||
LOGINTEXTS,
|
||||
// others
|
||||
PRIVACYPOLICY,
|
||||
LANGUAGES,
|
||||
OIDC,
|
||||
SECRETS,
|
||||
SECURITY,
|
||||
|
@ -88,7 +88,7 @@
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="preferredLanguage">
|
||||
<mat-option *ngFor="let language of languages" [value]="language">
|
||||
<mat-option *ngFor="let language of langSvc.supported$ | async" [value]="language">
|
||||
{{ 'LANGUAGES.' + language | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
|
@ -20,7 +20,7 @@ import { AdminService } from 'src/app/services/admin.service';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { supportedLanguages } from 'src/app/utils/language';
|
||||
import { LanguagesService } from '../../services/languages.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-org-create',
|
||||
@ -46,7 +46,6 @@ export class OrgCreateComponent {
|
||||
public pwdForm?: UntypedFormGroup;
|
||||
|
||||
public genders: Gender[] = [Gender.GENDER_FEMALE, Gender.GENDER_MALE, Gender.GENDER_UNSPECIFIED];
|
||||
public languages: string[] = supportedLanguages;
|
||||
|
||||
public policy?: PasswordComplexityPolicy.AsObject;
|
||||
public usePassword: boolean = false;
|
||||
@ -60,6 +59,7 @@ export class OrgCreateComponent {
|
||||
private _location: Location,
|
||||
private fb: UntypedFormBuilder,
|
||||
private mgmtService: ManagementService,
|
||||
public langSvc: LanguagesService,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
const instanceBread = new Breadcrumb({
|
||||
@ -70,10 +70,6 @@ export class OrgCreateComponent {
|
||||
|
||||
breadcrumbService.setBreadcrumb([instanceBread]);
|
||||
this.initForm();
|
||||
|
||||
this.adminService.getSupportedLanguages().then((supportedResp) => {
|
||||
this.languages = supportedResp.languagesList;
|
||||
});
|
||||
}
|
||||
|
||||
public createSteps: number = 2;
|
||||
|
@ -91,7 +91,7 @@
|
||||
<cnsl-form-field>
|
||||
<cnsl-label>{{ 'USER.PROFILE.PREFERRED_LANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="preferredLanguage">
|
||||
<mat-option *ngFor="let language of languages" [value]="language">
|
||||
<mat-option *ngFor="let language of langSvc.supported$ | async" [value]="language">
|
||||
{{ 'LANGUAGES.' + language | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
|
@ -2,7 +2,7 @@ import { Location } from '@angular/common';
|
||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subject, debounceTime } from 'rxjs';
|
||||
import { Subject, debounceTime, Observable } from 'rxjs';
|
||||
import { AddHumanUserRequest } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { Domain } from 'src/app/proto/generated/zitadel/org_pb';
|
||||
import { PasswordComplexityPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
@ -13,7 +13,6 @@ import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { CountryCallingCodesService, CountryPhoneCode } from 'src/app/services/country-calling-codes.service';
|
||||
import { formatPhone } from 'src/app/utils/formatPhone';
|
||||
import { supportedLanguages } from 'src/app/utils/language';
|
||||
import {
|
||||
containsLowerCaseValidator,
|
||||
containsNumberValidator,
|
||||
@ -25,6 +24,7 @@ import {
|
||||
phoneValidator,
|
||||
requiredValidator,
|
||||
} from '../../../modules/form-field/validators/validators';
|
||||
import { LanguagesService } from '../../../services/languages.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-user-create',
|
||||
@ -34,7 +34,6 @@ 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[] = supportedLanguages;
|
||||
public selected: CountryPhoneCode | undefined = {
|
||||
countryCallingCode: '1',
|
||||
countryCode: 'US',
|
||||
@ -61,6 +60,7 @@ export class UserCreateComponent implements OnInit, OnDestroy {
|
||||
private changeDetRef: ChangeDetectorRef,
|
||||
private _location: Location,
|
||||
private countryCallingCodesService: CountryCallingCodesService,
|
||||
public langSvc: LanguagesService,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
breadcrumbService.setBreadcrumb([
|
||||
@ -69,7 +69,6 @@ export class UserCreateComponent implements OnInit, OnDestroy {
|
||||
routerLink: ['/org'],
|
||||
}),
|
||||
]);
|
||||
|
||||
this.loading = true;
|
||||
this.loadOrg();
|
||||
this.mgmtService
|
||||
@ -88,10 +87,6 @@ export class UserCreateComponent implements OnInit, OnDestroy {
|
||||
this.loading = false;
|
||||
this.changeDetRef.detectChanges();
|
||||
});
|
||||
|
||||
this.mgmtService.getSupportedLanguages().then((lang) => {
|
||||
this.languages = lang.languagesList;
|
||||
});
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
|
@ -19,7 +19,12 @@
|
||||
|
||||
<div class="max-width-container">
|
||||
<cnsl-meta-layout>
|
||||
<cnsl-sidenav [(ngModel)]="currentSetting" [settingsList]="settingsList" queryParam="id">
|
||||
<cnsl-sidenav
|
||||
[(ngModel)]="currentSetting"
|
||||
[settingsList]="settingsList"
|
||||
queryParam="id"
|
||||
(ngModelChange)="settingChanged()"
|
||||
>
|
||||
<ng-container *ngIf="currentSetting === 'general'">
|
||||
<cnsl-card
|
||||
*ngIf="user && user.human && user.human.profile"
|
||||
@ -30,7 +35,7 @@
|
||||
[showEditImage]="true"
|
||||
[preferredLoginName]="user.preferredLoginName"
|
||||
[genders]="genders"
|
||||
[languages]="languages"
|
||||
[languages]="(langSvc.supported$ | async) || []"
|
||||
[username]="user.userName"
|
||||
[user]="user.human"
|
||||
[disabled]="false"
|
||||
|
@ -6,7 +6,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Buffer } from 'buffer';
|
||||
import { Subscription, take } from 'rxjs';
|
||||
import { from, Observable, Subscription, take } from 'rxjs';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { phoneValidator, requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||
import { InfoDialogComponent } from 'src/app/modules/info-dialog/info-dialog.component';
|
||||
@ -24,8 +24,8 @@ 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 { formatPhone } from 'src/app/utils/formatPhone';
|
||||
import { supportedLanguages } from 'src/app/utils/language';
|
||||
import { EditDialogComponent, EditDialogType } from './edit-dialog/edit-dialog.component';
|
||||
import { LanguagesService } from '../../../../services/languages.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-auth-user-detail',
|
||||
@ -35,7 +35,6 @@ 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[] = supportedLanguages;
|
||||
|
||||
private subscription: Subscription = new Subscription();
|
||||
|
||||
@ -65,6 +64,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
];
|
||||
public currentSetting: string | undefined = this.settingsList[0].id;
|
||||
public loginPolicy?: LoginPolicy.AsObject;
|
||||
private savedLanguage?: string;
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
@ -77,10 +77,12 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
private mediaMatcher: MediaMatcher,
|
||||
private _location: Location,
|
||||
activatedRoute: ActivatedRoute,
|
||||
public langSvc: LanguagesService,
|
||||
) {
|
||||
activatedRoute.queryParams.pipe(take(1)).subscribe((params: Params) => {
|
||||
const { id } = params;
|
||||
if (id) {
|
||||
this.cleanupTranslation();
|
||||
this.currentSetting = id;
|
||||
}
|
||||
});
|
||||
@ -97,10 +99,6 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
this.loading = true;
|
||||
this.refreshUser();
|
||||
|
||||
this.userService.getSupportedLanguages().then((lang) => {
|
||||
this.languages = lang.languagesList;
|
||||
});
|
||||
|
||||
this.userService.getMyLoginPolicy().then((policy) => {
|
||||
if (policy.policy) {
|
||||
this.loginPolicy = policy.policy;
|
||||
@ -109,6 +107,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
private changeSelection(small: boolean): void {
|
||||
this.cleanupTranslation();
|
||||
if (small) {
|
||||
this.currentSetting = undefined;
|
||||
} else {
|
||||
@ -138,6 +137,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
}),
|
||||
]);
|
||||
}
|
||||
this.savedLanguage = resp.user?.human?.profile?.preferredLanguage;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -147,9 +147,22 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.cleanupTranslation();
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
|
||||
public settingChanged(): void {
|
||||
this.cleanupTranslation();
|
||||
}
|
||||
|
||||
private cleanupTranslation(): void {
|
||||
if (this?.savedLanguage) {
|
||||
this.translate.use(this?.savedLanguage);
|
||||
} else {
|
||||
this.translate.use(this.translate.defaultLang);
|
||||
}
|
||||
}
|
||||
|
||||
public changeUsername(): void {
|
||||
const dialogRef = this.dialog.open(EditDialogComponent, {
|
||||
data: {
|
||||
@ -193,6 +206,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
)
|
||||
.then(() => {
|
||||
this.toast.showInfo('USER.TOAST.SAVED', true);
|
||||
this.savedLanguage = this.user?.human?.profile?.preferredLanguage;
|
||||
this.refreshChanges$.emit();
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -83,7 +83,7 @@
|
||||
[preferredLoginName]="user.preferredLoginName"
|
||||
[disabled]="(canWrite$ | async) === false"
|
||||
[genders]="genders"
|
||||
[languages]="languages"
|
||||
[languages]="(langSvc.supported$ | async) || []"
|
||||
[username]="user.userName"
|
||||
[user]="user.human"
|
||||
(submitData)="saveProfile($event)"
|
||||
|
@ -22,10 +22,11 @@ import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { formatPhone } from 'src/app/utils/formatPhone';
|
||||
import { supportedLanguages } from 'src/app/utils/language';
|
||||
import { EditDialogComponent, EditDialogType } from '../auth-user-detail/edit-dialog/edit-dialog.component';
|
||||
import { ResendEmailDialogComponent } from '../auth-user-detail/resend-email-dialog/resend-email-dialog.component';
|
||||
import { MachineSecretDialogComponent } from './machine-secret-dialog/machine-secret-dialog.component';
|
||||
import { Observable } from 'rxjs';
|
||||
import { LanguagesService } from '../../../../services/languages.service';
|
||||
|
||||
const GENERAL: SidenavSetting = { id: 'general', i18nKey: 'USER.SETTINGS.GENERAL' };
|
||||
const GRANTS: SidenavSetting = { id: 'grants', i18nKey: 'USER.SETTINGS.USERGRANTS' };
|
||||
@ -45,7 +46,6 @@ 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[] = supportedLanguages;
|
||||
|
||||
public ChangeType: any = ChangeType;
|
||||
|
||||
@ -76,6 +76,7 @@ export class UserDetailComponent implements OnInit {
|
||||
private router: Router,
|
||||
activatedRoute: ActivatedRoute,
|
||||
private mediaMatcher: MediaMatcher,
|
||||
public langSvc: LanguagesService,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
activatedRoute.queryParams.pipe(take(1)).subscribe((params: Params) => {
|
||||
@ -100,10 +101,6 @@ export class UserDetailComponent implements OnInit {
|
||||
this.mediaMatcher.matchMedia(mediaq).onchange = (small) => {
|
||||
this.changeSelection(small.matches);
|
||||
};
|
||||
|
||||
this.mgmtUserService.getSupportedLanguages().then((lang) => {
|
||||
this.languages = lang.languagesList;
|
||||
});
|
||||
}
|
||||
|
||||
private changeSelection(small: boolean): void {
|
||||
|
@ -309,6 +309,7 @@ export class UserTableComponent implements OnInit {
|
||||
setTimeout(() => {
|
||||
this.refreshPage();
|
||||
}, 1000);
|
||||
this.selection.clear();
|
||||
this.toast.showInfo('USER.TOAST.DELETED', true);
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -54,6 +54,8 @@ import {
|
||||
DeactivateSMSProviderResponse,
|
||||
DeleteProviderRequest,
|
||||
DeleteProviderResponse,
|
||||
GetAllowedLanguagesRequest,
|
||||
GetAllowedLanguagesResponse,
|
||||
GetCustomDomainClaimedMessageTextRequest,
|
||||
GetCustomDomainClaimedMessageTextResponse,
|
||||
GetCustomDomainPolicyRequest,
|
||||
@ -126,6 +128,7 @@ import {
|
||||
GetPrivacyPolicyResponse,
|
||||
GetProviderByIDRequest,
|
||||
GetProviderByIDResponse,
|
||||
GetRestrictionsResponse,
|
||||
GetSecretGeneratorRequest,
|
||||
GetSecretGeneratorResponse,
|
||||
GetSecurityPolicyRequest,
|
||||
@ -192,6 +195,7 @@ import {
|
||||
ResetCustomDomainPolicyToDefaultResponse,
|
||||
ResetCustomLoginTextsToDefaultRequest,
|
||||
ResetCustomLoginTextsToDefaultResponse,
|
||||
SelectLanguages,
|
||||
SetCustomLoginTextsRequest,
|
||||
SetCustomLoginTextsResponse,
|
||||
SetDefaultDomainClaimedMessageTextRequest,
|
||||
@ -216,6 +220,8 @@ import {
|
||||
SetDefaultVerifyPhoneMessageTextResponse,
|
||||
SetDefaultVerifySMSOTPMessageTextRequest,
|
||||
SetDefaultVerifySMSOTPMessageTextResponse,
|
||||
SetRestrictionsRequest,
|
||||
SetRestrictionsResponse,
|
||||
SetSecurityPolicyRequest,
|
||||
SetSecurityPolicyResponse,
|
||||
SetUpOrgRequest,
|
||||
@ -433,6 +439,11 @@ export class AdminService {
|
||||
return this.grpcService.admin.getSupportedLanguages(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getAllowedLanguages(): Promise<GetAllowedLanguagesResponse.AsObject> {
|
||||
const req = new GetAllowedLanguagesRequest();
|
||||
return this.grpcService.admin.getAllowedLanguages(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getDefaultLoginTexts(req: GetDefaultLoginTextsRequest): Promise<GetDefaultLoginTextsResponse.AsObject> {
|
||||
return this.grpcService.admin.getDefaultLoginTexts(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
@ -823,6 +834,29 @@ export class AdminService {
|
||||
return this.grpcService.admin.setDefaultLanguage(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
/* restrictions */
|
||||
|
||||
public getRestrictions(): Promise<GetRestrictionsResponse.AsObject> {
|
||||
const req = new GetDefaultLanguageRequest();
|
||||
return this.grpcService.admin.getRestrictions(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public setRestrictions(
|
||||
disallowPublicOrgRegistration?: boolean,
|
||||
allowedLanguages?: string[],
|
||||
): Promise<SetRestrictionsResponse.AsObject> {
|
||||
const req = new SetRestrictionsRequest();
|
||||
if (disallowPublicOrgRegistration !== undefined) {
|
||||
req.setDisallowPublicOrgRegistration(disallowPublicOrgRegistration);
|
||||
}
|
||||
if (allowedLanguages !== undefined) {
|
||||
const langs = new SelectLanguages();
|
||||
langs.setListList(allowedLanguages);
|
||||
req.setAllowedLanguages(langs);
|
||||
}
|
||||
return this.grpcService.admin.setRestrictions(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
/* notification policy */
|
||||
|
||||
public getNotificationPolicy(): Promise<GetNotificationPolicyResponse.AsObject> {
|
||||
|
@ -32,8 +32,6 @@ import {
|
||||
GetMyProfileResponse,
|
||||
GetMyUserRequest,
|
||||
GetMyUserResponse,
|
||||
GetSupportedLanguagesRequest,
|
||||
GetSupportedLanguagesResponse,
|
||||
ListMyAuthFactorsRequest,
|
||||
ListMyAuthFactorsResponse,
|
||||
ListMyLinkedIDPsRequest,
|
||||
@ -494,11 +492,6 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.resendMyEmailVerification(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getSupportedLanguages(): Promise<GetSupportedLanguagesResponse.AsObject> {
|
||||
const req = new GetSupportedLanguagesRequest();
|
||||
return this.grpcService.auth.getSupportedLanguages(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getMyLoginPolicy(): Promise<GetMyLoginPolicyResponse.AsObject> {
|
||||
const req = new GetMyLoginPolicyRequest();
|
||||
return this.grpcService.auth.getMyLoginPolicy(req, null).then((resp) => resp.toObject());
|
||||
|
46
console/src/app/services/languages.service.ts
Normal file
46
console/src/app/services/languages.service.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { forkJoin, Observable, ReplaySubject, Subscription } from 'rxjs';
|
||||
import { map, withLatestFrom } from 'rxjs/operators';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AdminService } from './admin.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LanguagesService {
|
||||
private supportedSubject$ = new ReplaySubject<string[]>(1);
|
||||
public supported$: Observable<string[]> = this.supportedSubject$.asObservable();
|
||||
private allowedSubject$ = new ReplaySubject<string[]>(1);
|
||||
public allowed$: Observable<string[]> = this.allowedSubject$.asObservable();
|
||||
public notAllowed$: Observable<string[]> = this.allowed$.pipe(
|
||||
withLatestFrom(this.supported$),
|
||||
map(([allowed, supported]) => {
|
||||
return supported.filter((s) => !allowed.includes(s));
|
||||
}),
|
||||
);
|
||||
public restricted$: Observable<boolean> = this.notAllowed$.pipe(
|
||||
map((notallowed) => {
|
||||
return notallowed.length > 0;
|
||||
}),
|
||||
);
|
||||
|
||||
constructor(private adminSvc: AdminService) {
|
||||
const sub: Subscription = forkJoin([
|
||||
this.adminSvc.getSupportedLanguages(),
|
||||
this.adminSvc.getAllowedLanguages(),
|
||||
]).subscribe({
|
||||
next: ([{ languagesList: supported }, { languagesList: allowed }]) => {
|
||||
this.supportedSubject$.next(supported);
|
||||
this.allowedSubject$.next(allowed);
|
||||
},
|
||||
complete: () => sub.unsubscribe(),
|
||||
});
|
||||
}
|
||||
|
||||
public newAllowed(languages: string[]) {
|
||||
this.allowedSubject$.next(languages);
|
||||
}
|
||||
|
||||
public isNotAllowed(language: string): Observable<boolean> {
|
||||
return this.notAllowed$.pipe(map((notAllowed) => notAllowed.includes(language)));
|
||||
}
|
||||
}
|
@ -551,11 +551,6 @@ export class ManagementService {
|
||||
|
||||
constructor(private readonly grpcService: GrpcService) {}
|
||||
|
||||
public getSupportedLanguages(): Promise<GetSupportedLanguagesResponse.AsObject> {
|
||||
const req = new GetSupportedLanguagesRequest();
|
||||
return this.grpcService.mgmt.getSupportedLanguages(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getDefaultLoginTexts(req: GetDefaultLoginTextsRequest): Promise<GetDefaultLoginTextsResponse.AsObject> {
|
||||
return this.grpcService.mgmt.getDefaultLoginTexts(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ export class ToastService {
|
||||
}
|
||||
}
|
||||
|
||||
public showError(error: any | string, isGrpc: boolean = true, i18nKey: boolean = false): void {
|
||||
public showError = (error: any | string, isGrpc: boolean = true, i18nKey: boolean = false) => {
|
||||
if (isGrpc) {
|
||||
const { message, code, metadata } = error;
|
||||
if (code !== 16) {
|
||||
@ -57,7 +57,7 @@ export class ToastService {
|
||||
} else {
|
||||
this.showMessage(error as string, '', false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private showMessage(message: string, action: string, success: boolean): Observable<void> {
|
||||
const ref = this.snackBar.open(message, action, {
|
||||
|
@ -865,14 +865,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Последователност",
|
||||
"CHECKBOX": "Филтриране по последователност",
|
||||
"SORT": "Сортиране",
|
||||
"ASC": "Възходящ",
|
||||
"DESC": "Спускане"
|
||||
"CHECKBOX": "Филтриране по последователност"
|
||||
},
|
||||
"SORT": "Сортиране",
|
||||
"ASC": "Възходящ",
|
||||
"DESC": "Спускане",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Дата на създаване",
|
||||
"CHECKBOX": "Филтриране по дата на създаване"
|
||||
"RADIO_FROM": "От",
|
||||
"RADIO_RANGE": "Обхват",
|
||||
"LABEL_SINCE": "От",
|
||||
"LABEL_UNTIL": "До"
|
||||
},
|
||||
"OTHER": "друго",
|
||||
"OTHERS": "други"
|
||||
@ -922,20 +924,22 @@
|
||||
"BTN": "Преименуване"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Проверка на собствеността върху домейна на организацията",
|
||||
"VERIFICATION": "За да потвърдите собствеността на вашия домейн, трябва да изтеглите файл за проверка и да го качите на предоставения URL адрес, посочен по-долу, или да поставите DNS запис в TXT запис за предоставения URL адрес. ",
|
||||
"VERIFICATION_SKIP": "Можете да пропуснете проверката засега и да продължите да създавате вашата организация, но за да използвате вашата организация, тази стъпка трябва да бъде завършена!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Токените се проверяват редовно, за да се гарантира, че все още сте собственик на домейна.",
|
||||
"TITLE": "Потвърдете собствеността на {{value}}",
|
||||
"VERIFICATION": "Предлагаме ви два метода за ръчно валидиране на вашия домейн:",
|
||||
"VERIFICATION_HTML": "- HTTP. Хоствайте временен файл за проверка на уебсайта си",
|
||||
"VERIFICATION_DNS": "- DNS. Създайте DNS запис за TXT запис",
|
||||
"VERIFICATION_DNS_DESC": "Ако управлявате {{ value }} и имате достъп до вашите DNS записи, можете да създадете нов TXT запис със следните стойности:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Използвайте този код за стойността на TXT записа:",
|
||||
"VERIFICATION_HTTP_DESC": "Ако имате достъп до хостинг на уебсайта си, просто изтеглете файла за проверка и го качете на предоставения URL адрес",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "Очакван URL адрес:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Файл за проверка:",
|
||||
"VERIFICATION_SKIP": "Можете да пропуснете проверката засега и да продължите да създавате вашата организация, но за да използвате домейна си, тази стъпка трябва да бъде изпълнена!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Не изтривайте кода за потвърждение, тъй като ZITADEL ще проверява отново собствеността на вашия домейн от време на време.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Поискайте нов токен",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Ако искате да поискате нов токен, изберете предпочитания от вас метод. ",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Вече е заявен токен за потвърждение. ",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Тип на токена:",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Методът {{ value }} е избран за потвърждение на вашия домейн. Щракнете върху бутона, за да задействате проверка за проверка или да нулирате процеса на проверка.",
|
||||
"VERIFICATION_SUCCESSFUL": "Домейнът е успешно проверен!",
|
||||
"REQUESTNEWTOKEN": "Поискайте нов токен",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "Нулирайте метода за проверка"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Свали файл",
|
||||
"SELECTORGTOOLTIP": "Изберете тази организация.",
|
||||
@ -1012,7 +1016,7 @@
|
||||
"DESCRIPTION": "Тези настройки разширяват и презаписват настройките на вашия екземпляр."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Общ",
|
||||
"LANGUAGES": "Езици",
|
||||
"LOGIN": "Поведение при влизане и сигурност",
|
||||
"LOCKOUT": "Блокиране",
|
||||
"COMPLEXITY": "Сложност на паролата",
|
||||
@ -1041,22 +1045,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Език по подразбиране",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "Английски",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Италиано",
|
||||
"ja": "日本語",
|
||||
"pl": "Полски",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Настройки на езика",
|
||||
"DEFAULT": "Език по подразбиране",
|
||||
"ALLOWED": "Разрешени езици",
|
||||
"NOT_ALLOWED": "Не са разрешени езици",
|
||||
"ALLOW_ALL": "Разрешете всички езици",
|
||||
"DISALLOW_ALL": "Забранете всички езици",
|
||||
"SETASDEFAULT": "Задайте като език по подразбиране",
|
||||
"DEFAULT_SAVED": "Езикът по подразбиране е запазен успешно.",
|
||||
"ALLOWED_SAVED": "Разрешените езици са запазени успешно.",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "Английски",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Италиано",
|
||||
"ja": "日本語",
|
||||
"pl": "Полски",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP настройки",
|
||||
@ -1255,8 +1269,10 @@
|
||||
"RESET_DESCRIPTION": "На път сте да възстановите всички стойности по подразбиране. ",
|
||||
"UNSAVED_TITLE": "Продължаване без запазване?",
|
||||
"UNSAVED_DESCRIPTION": "Направихте промени без да запазите. ",
|
||||
"LOCALE": "Локален код",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Избрахте език, който не е разрешен. Можете да продължите да променяте текстовете. Но ако искате вашите потребители да могат да използват този език, променете ограниченията на вашите екземпляри.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Не е разрешено:",
|
||||
"LANGUAGE": "Език",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "Английски",
|
||||
"es": "Español",
|
||||
@ -1367,7 +1383,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP адресът на изпращача съвпада с домейна на екземпляра",
|
||||
"ALLOWUSERNAMEPASSWORD": "Потребителско име Паролата е разрешена",
|
||||
"ALLOWEXTERNALIDP": "Допуска се външен IDP",
|
||||
"ALLOWREGISTER": "Регистрацията е разрешена",
|
||||
"ALLOWREGISTERUSERS": "Регистрирайте потребители",
|
||||
"ALLOWREGISTERORGS": "Регистрирайте организации",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "Разрешено е конвенционалното влизане с потребителско име и парола.",
|
||||
"ALLOWEXTERNALIDP_DESC": "Входът е разрешен за основните доставчици на самоличност",
|
||||
"ALLOWREGISTER_DESC": "Ако опцията е избрана, в входа се появява допълнителна стъпка за регистрация на потребител.",
|
||||
|
@ -872,14 +872,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Sekvence",
|
||||
"CHECKBOX": "Filtrovat podle Sekvence",
|
||||
"SORT": "Třídění",
|
||||
"ASC": "Vzestupně",
|
||||
"DESC": "Sestupně"
|
||||
"CHECKBOX": "Filtrovat podle Sekvence"
|
||||
},
|
||||
"SORT": "Třídění",
|
||||
"ASC": "Vzestupně",
|
||||
"DESC": "Sestupně",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Datum vytvoření",
|
||||
"CHECKBOX": "Filtrovat podle Datumu vytvoření"
|
||||
"RADIO_FROM": "Od",
|
||||
"RADIO_RANGE": "Rozsah",
|
||||
"LABEL_SINCE": "Od",
|
||||
"LABEL_UNTIL": "Do"
|
||||
},
|
||||
"OTHER": "jiný",
|
||||
"OTHERS": "jiné"
|
||||
@ -929,20 +931,22 @@
|
||||
"BTN": "Přejmenovat"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Ověření vlastnictví domény organizace",
|
||||
"VERIFICATION": "Pro ověření vlastnictví vaší domény je potřeba stáhnout ověřovací soubor a nahrát jej na uvedené URL níže, nebo umístit záznam TXT Record DNS pro uvedené URL. Pro dokončení klikněte na tlačítko a proveďte ověření.",
|
||||
"VERIFICATION_SKIP": "Ověření můžete nyní přeskočit a pokračovat ve vytváření vaší organizace, ale pro používání vaší organizace je třeba tento krok dokončit!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Tokeny jsou pravidelně kontrolovány, aby bylo zajištěno, že jste stále vlastníkem domény.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Požádat o nový token",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Pokud si přejete požádat o nový token, vyberte preferovanou metodu. Pokud chcete ověřit stávající token, klikněte na tlačítko výše.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Token pro ověření byl již požadován. Klikněte na tlačítko a spusťte ověřovací kontrolu.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Typ tokenu:",
|
||||
"TITLE": "Ověřte vlastnictví {{value}}",
|
||||
"VERIFICATION": "Nabízíme vám dva způsoby ručního ověření domény:",
|
||||
"VERIFICATION_HTML": "- HTTP. Hostujte na svém webu dočasný ověřovací soubor",
|
||||
"VERIFICATION_DNS": "- DNS. Vytvořte záznam DNS záznamu TXT",
|
||||
"VERIFICATION_DNS_DESC": "Pokud spravujete {{ value }} a máte přístup ke svým záznamům DNS, můžete vytvořit nový záznam TXT s následujícími hodnotami:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Pro hodnotu TXT záznamu použijte tento kód:",
|
||||
"VERIFICATION_HTTP_DESC": "Pokud máte přístup k hostování svých webových stránek, jednoduše si stáhněte ověřovací soubor a nahrajte jej na uvedenou adresu URL",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "Očekávaná adresa URL:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Ověřovací soubor:",
|
||||
"VERIFICATION_SKIP": "Ověření můžete zatím přeskočit a pokračovat ve vytváření organizace, ale abyste mohli používat svou doménu, musíte tento krok dokončit!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Nemažte ověřovací kód, protože ZITADEL čas od času znovu zkontroluje vlastnictví vaší domény.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Vyžádejte si nový token",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Pro ověření vaší domény byla vybrána metoda {{ value }}. Kliknutím na tlačítko spustíte kontrolu ověření nebo resetujete proces ověření.",
|
||||
"VERIFICATION_SUCCESSFUL": "Doména byla úspěšně ověřena!",
|
||||
"REQUESTNEWTOKEN": "Požadovat nový token",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "Resetovat metodu ověření"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Stáhnout soubor",
|
||||
"SELECTORGTOOLTIP": "Vybrat tuto organizaci.",
|
||||
@ -1019,7 +1023,7 @@
|
||||
"DESCRIPTION": "Tato nastavení rozšiřují a přepisují nastavení vaší instance."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Obecné",
|
||||
"LANGUAGES": "Jazyky",
|
||||
"LOGIN": "Chování při přihlášení a bezpečnost",
|
||||
"LOCKOUT": "Blokování",
|
||||
"COMPLEXITY": "Složitost hesla",
|
||||
@ -1048,22 +1052,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Výchozí jazyk",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Nastavení jazyka",
|
||||
"DEFAULT": "Výchozí jazyk",
|
||||
"ALLOWED": "Povolené jazyky",
|
||||
"NOT_ALLOWED": "Nepovolené jazyky",
|
||||
"ALLOW_ALL": "Povolit všechny jazyky",
|
||||
"DISALLOW_ALL": "Zakázat všechny jazyky",
|
||||
"SETASDEFAULT": "Nastavit jako výchozí",
|
||||
"DEFAULT_SAVED": "Výchozí jazyk byl úspěšně nastaven.",
|
||||
"ALLOWED_SAVED": "Povolené jazyky byly úspěšně nastaveny.",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Nastavení SMTP",
|
||||
@ -1262,8 +1276,10 @@
|
||||
"RESET_DESCRIPTION": "Chystáte se obnovit všechny výchozí hodnoty. Všechny vaše změny budou trvale smazány. Opravdu chcete pokračovat?",
|
||||
"UNSAVED_TITLE": "Pokračovat bez uložení?",
|
||||
"UNSAVED_DESCRIPTION": "Provedli jste změny bez uložení. Chcete je nyní uložit?",
|
||||
"LOCALE": "Kód jazyka",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Vybrali jste jazyk, který není povolen. Můžete pokračovat v úpravách textů. Ale pokud chcete, aby vaši uživatelé mohli tento jazyk skutečně používat, změňte omezení vašich instancí.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Nepovolené jazyky:",
|
||||
"LANGUAGE": "Jazyk",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1375,6 +1391,8 @@
|
||||
"ALLOWUSERNAMEPASSWORD": "Povoleno uživatelské jméno a heslo",
|
||||
"ALLOWEXTERNALIDP": "Povoleno externí IDP",
|
||||
"ALLOWREGISTER": "Registrace povolena",
|
||||
"ALLOWREGISTERUSERS": "Registrace uživatelů povolena",
|
||||
"ALLOWREGISTERORGS": "Registrace organizací povolena",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "Je povoleno klasické přihlášení s uživatelským jménem a heslem.",
|
||||
"ALLOWEXTERNALIDP_DESC": "Přihlášení je povoleno pro níže uvedené poskytovatele identity.",
|
||||
"ALLOWREGISTER_DESC": "Pokud je možnost vybrána, objeví se při přihlášení další krok pro registraci uživatele.",
|
||||
|
@ -871,14 +871,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Sequenz",
|
||||
"CHECKBOX": "Nach Sequenz filtern",
|
||||
"SORT": "Sortierung",
|
||||
"ASC": "aufsteigend",
|
||||
"DESC": "absteigend"
|
||||
"CHECKBOX": "Nach Sequenz filtern"
|
||||
},
|
||||
"SORT": "Sortierung",
|
||||
"ASC": "Aufsteigend",
|
||||
"DESC": "Absteigend",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Erstelldatum",
|
||||
"CHECKBOX": "Nach Erstelldatum filtern"
|
||||
"RADIO_FROM": "Von",
|
||||
"RADIO_RANGE": "Zeitraum",
|
||||
"LABEL_SINCE": "Seit",
|
||||
"LABEL_UNTIL": "Bis"
|
||||
},
|
||||
"OTHER": "weiterer",
|
||||
"OTHERS": "weitere"
|
||||
@ -928,20 +930,22 @@
|
||||
"BTN": "Umbenennen"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Verifikation der Domain der Organisation",
|
||||
"VERIFICATION": "Überprüfe den Besitz Deiner Domain, indem Du eine Bestätigungsdatei herunterlädst und unter der angegebenen URL speicherst, oder indem Du sie mit einem DNS-Eintrag verifizierst.",
|
||||
"VERIFICATION_SKIP": "Du kannst die Überprüfung vorerst überspringen und Deine Organisation erstellen. Um Deine Organisation jedoch verwenden zu können, muss dieser Schritt abgeschlossen sein.",
|
||||
"VERIFICATION_VALIDATION_DESC": "Die Tokens werden regelmässig überprüft, um sicherzustellen, dass Du weiterhin im Besitz der Domain bist.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Neues Token anfordern",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Wenn Du ein neues Token anfordern willst, klicke auf die gewünschte Methode. Wenn Du ein vorhandenes Token validieren möchtest, klicke auf \"Verifizieren\".",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Ein Token zur Validierung wurde bereits angefragt. Klicke auf \"Verifizieren\", um dieses Token zu validieren.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Typ des Tokens:",
|
||||
"VERIFICATION_SUCCESSFUL": "Domain erfolgreich validiert!",
|
||||
"REQUESTNEWTOKEN": "Neues Token anfordern",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"TITLE": "Bestätigen Sie die Inhaberschaft von {{value}}",
|
||||
"VERIFICATION": "Wir bieten Ihnen zwei Methoden zur manuellen Validierung Ihrer Domain:",
|
||||
"VERIFICATION_HTML": "- HTTP. Hosten Sie eine temporäre Verifizierungsdatei auf Ihrer Website",
|
||||
"VERIFICATION_DNS": "- DNS. Erstellen Sie einen DNS-Eintrag für den TXT-Eintrag",
|
||||
"VERIFICATION_DNS_DESC": "Wenn Sie {{ value }} verwalten und Zugriff auf Ihre DNS-Einträge haben, können Sie einen neuen TXT-Eintrag mit den folgenden Werten erstellen:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Verwenden Sie diesen Code für den Wert des TXT-Datensatzes:",
|
||||
"VERIFICATION_HTTP_DESC": "Wenn Sie Zugriff auf das Hosting Ihrer Website haben, laden Sie einfach die Bestätigungsdatei herunter und laden Sie sie unter der angegebenen URL hoch",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "Erwartete URL:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Verifizierungsdatei:",
|
||||
"VERIFICATION_SKIP": "Sie können die Verifizierung vorerst überspringen und mit der Erstellung Ihrer Organisation fortfahren, aber um Ihre Domain nutzen zu können, muss dieser Schritt abgeschlossen sein!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Löschen Sie den Bestätigungscode nicht, da ZITADEL die Inhaberschaft Ihrer Domain von Zeit zu Zeit erneut überprüft.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Fordern Sie ein neues Token an",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Zur Verifizierung Ihrer Domain wurde die Methode {{ value }} ausgewählt. Klicken Sie auf die Schaltfläche, um eine Verifizierungsprüfung auszulösen oder den Verifizierungsprozess zurückzusetzen.",
|
||||
"VERIFICATION_SUCCESSFUL": "Domain erfolgreich verifiziert!",
|
||||
"RESETMETHOD": "Verifizierungsmethode zurücksetzen"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Datei herunterladen",
|
||||
"SELECTORGTOOLTIP": "Diese Organisation auswählen",
|
||||
@ -1018,7 +1022,7 @@
|
||||
"DESCRIPTION": "Diese Einstellungen erweitern bzw. überschreiben die Einstellungen Ihrer Instanz."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Allgemein",
|
||||
"LANGUAGES": "Sprachen",
|
||||
"LOGIN": "Loginverhalten und Sicherheit",
|
||||
"LOCKOUT": "Sperrmechanismen",
|
||||
"COMPLEXITY": "Passwordkomplexität",
|
||||
@ -1047,22 +1051,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Standardsprache",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Spracheinstellungen",
|
||||
"DEFAULT": "Standardsprache",
|
||||
"ALLOWED": "Erlaubte Sprachen",
|
||||
"NOT_ALLOWED": "Nicht erlaubte Sprachen",
|
||||
"ALLOW_ALL": "Alle Sprachen erlauben",
|
||||
"DISALLOW_ALL": "Alle Sprachen verbieten",
|
||||
"SETASDEFAULT": "Als Standard setzen",
|
||||
"DEFAULT_SAVED": "Standard Sprache gesetzt",
|
||||
"ALLOWED_SAVED": "Erlaubte Sprachen gesetzt",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP Einstellungen",
|
||||
@ -1261,8 +1275,10 @@
|
||||
"RESET_DESCRIPTION": "Sie sind im Begriff alle Standardwerte wiederherzustellen. Alle von Ihnen gesetzten Änderungen werden unwiderruflich gelöscht. Wollen Sie fortfahren?",
|
||||
"UNSAVED_TITLE": "Ohne speichern fortfahren?",
|
||||
"UNSAVED_DESCRIPTION": "Sie haben Änderungen vorgenommen ohne zu speichern. Möchten Sie jetzt speichern?",
|
||||
"LOCALE": "Sprachcode",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Sie haben eine Sprache ausgewählt, die nicht erlaubt ist. Sie können weiterhin die Texte ändern. Wenn Sie jedoch möchten, dass Ihre Benutzer diese Sprache tatsächlich verwenden können, ändern Sie die Einschränkungen Ihrer Instanz.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Nicht erlaubt:",
|
||||
"LANGUAGE": "Sprache",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1373,7 +1389,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP Sender Adresse entspricht Instanzdomain",
|
||||
"ALLOWUSERNAMEPASSWORD": "Benutzername Passwort erlaubt",
|
||||
"ALLOWEXTERNALIDP": "Externer IDP erlaubt",
|
||||
"ALLOWREGISTER": "Registrieren erlaubt",
|
||||
"ALLOWREGISTERUSERS": "Benutzerregistrierung erlaubt",
|
||||
"ALLOWREGISTERORGS": "Organisationsregistrierung erlaubt",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "Der konventionelle Login mit Benutzername und Passwort wird erlaubt.",
|
||||
"ALLOWEXTERNALIDP_DESC": "Der Login wird für die darunter liegenden Identitätsanbieter erlaubt.",
|
||||
"ALLOWREGISTER_DESC": "Ist die Option gewählt, erscheint im Login ein zusätzlicher Schritt zum Registrieren eines Benutzers.",
|
||||
|
@ -872,14 +872,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Sequence",
|
||||
"CHECKBOX": "Filter by Sequence",
|
||||
"SORT": "Sorting",
|
||||
"ASC": "Ascending",
|
||||
"DESC": "Descending"
|
||||
"CHECKBOX": "Filter by Sequence"
|
||||
},
|
||||
"SORT": "Sort",
|
||||
"ASC": "Ascending",
|
||||
"DESC": "Descending",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Creation Date",
|
||||
"CHECKBOX": "Filter by Creation Date"
|
||||
"RADIO_FROM": "From",
|
||||
"RADIO_RANGE": "Range",
|
||||
"LABEL_SINCE": "Since",
|
||||
"LABEL_UNTIL": "Until"
|
||||
},
|
||||
"OTHER": "other",
|
||||
"OTHERS": "others"
|
||||
@ -929,20 +931,22 @@
|
||||
"BTN": "Rename"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Organization Domain Ownership Verification",
|
||||
"VERIFICATION": "To verify the ownership of your domain, you need to download a verification file and upload it at the provided URL listed below, or place a TXT Record DNS entry for the provided URL. To complete, click the button to verify.",
|
||||
"VERIFICATION_SKIP": "You can skip verification for now and continue to create your organization, but in order to use your organization this step has to be completed!",
|
||||
"VERIFICATION_VALIDATION_DESC": "The tokens are checked regularly to ensure you are still owner of the domain.",
|
||||
"TITLE": "Verify {{value}} ownership",
|
||||
"VERIFICATION": "We offer you two methods to manually validate your domain:",
|
||||
"VERIFICATION_HTML": "- HTTP. Host a temporary verification file on your website",
|
||||
"VERIFICATION_DNS": "- DNS. Create a TXT Record DNS entry",
|
||||
"VERIFICATION_DNS_DESC": "If you manage {{ value }} and you have access to your DNS records, you can create a new TXT record with the following values:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Use this code for the value of the TXT record:",
|
||||
"VERIFICATION_HTTP_DESC": "If you have access to your website hosting, simply download the verification file and upload it at the provided URL",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "Expected URL:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Verification file:",
|
||||
"VERIFICATION_SKIP": "You can skip verification for now and continue to create your organization, but in order to use your domain this step has to be completed!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Do not delete the verification code, as ZITADEL will re-check the ownership of your domain from time to time.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Request New Token",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "If you want to request a new token, select you preferred method. If you want to validate a persisting token, click the button above.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "A verification token has already been requested. Click on the button to trigger a verification check.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Type of the token:",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "The {{ value }} method has been selected to verify your domain. Click on the button to trigger a verification check or reset the verification process.",
|
||||
"VERIFICATION_SUCCESSFUL": "Domain successfully verified!",
|
||||
"REQUESTNEWTOKEN": "Request new token",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "Reset verification method"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Download File",
|
||||
"SELECTORGTOOLTIP": "Select this organization.",
|
||||
@ -1019,7 +1023,7 @@
|
||||
"DESCRIPTION": "These settings extend and overwrite your instance settings."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "General",
|
||||
"LANGUAGES": "Languages",
|
||||
"LOGIN": "Login Behavior and Security",
|
||||
"LOCKOUT": "Lockout",
|
||||
"COMPLEXITY": "Password complexity",
|
||||
@ -1048,22 +1052,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Default Language",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Language Settings",
|
||||
"DEFAULT": "Default Language",
|
||||
"ALLOWED": "Allowed Languages",
|
||||
"NOT_ALLOWED": "Not Allowed Languages",
|
||||
"ALLOW_ALL": "Allow All",
|
||||
"DISALLOW_ALL": "Disallow All",
|
||||
"SETASDEFAULT": "Set as Default Language",
|
||||
"DEFAULT_SAVED": "Default Language saved",
|
||||
"ALLOWED_SAVED": "Allowed Languages saved",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP Settings",
|
||||
@ -1262,8 +1276,10 @@
|
||||
"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": "You have made changes without saving. Do you want to save now?",
|
||||
"LOCALE": "Locale Code",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "You selected a language that is not allowed. You can go on modifying the texts. But if you want your users to actually be able to use this language, change your instances restrictions.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Not allowed:",
|
||||
"LANGUAGE": "Language",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1374,7 +1390,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP Sender Address matches Instance Domain",
|
||||
"ALLOWUSERNAMEPASSWORD": "Username Password allowed",
|
||||
"ALLOWEXTERNALIDP": "External IDP allowed",
|
||||
"ALLOWREGISTER": "Register allowed",
|
||||
"ALLOWREGISTERUSERS": "Register users allowed",
|
||||
"ALLOWREGISTERORGS": "Register organizations allowed",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "The conventional login with user name and password is allowed.",
|
||||
"ALLOWEXTERNALIDP_DESC": "The login is allowed for the underlying identity providers",
|
||||
"ALLOWREGISTER_DESC": "If the option is selected, an additional step for registering a user appears in the login.",
|
||||
|
@ -872,14 +872,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Secuencia",
|
||||
"CHECKBOX": "Filtrar por secuencia",
|
||||
"SORT": "Ordenado",
|
||||
"ASC": "Ascendente",
|
||||
"DESC": "Descendente"
|
||||
"CHECKBOX": "Filtrar por secuencia"
|
||||
},
|
||||
"SORT": "Ordenado",
|
||||
"ASC": "Ascendente",
|
||||
"DESC": "Descendente",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Fecha de creación",
|
||||
"CHECKBOX": "Filtrar por fecha de creación"
|
||||
"RADIO_FROM": "Desde",
|
||||
"RADIO_RANGE": "Rango",
|
||||
"LABEL_SINCE": "Desde",
|
||||
"LABEL_UNTIL": "Hasta"
|
||||
},
|
||||
"OTHER": "otro",
|
||||
"OTHERS": "otros"
|
||||
@ -929,20 +931,23 @@
|
||||
"BTN": "Renombrar"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Verificación de la propiedad del dominio de la organización",
|
||||
"VERIFICATION": "Para verificar la propiedad de tu dominio, necesitas descargar un fichero de verificación y subirlo a la URL proporcionada a continuación, o crear un registro DNS de tipo TXT que contenga la URL proporcionada. Para completar este paso, haz clic en el botón para verificarlo.",
|
||||
"VERIFICATION_SKIP": "Puedes saltarte esta verificación por ahora y continuar con la creación de tu organización, pero para poder utilizar esta organización ¡deberás completar este paso!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Los tokens se comprueban regularmente para asegurar que todavía eres el dueño del dominio.",
|
||||
"TITLE": "Verifica la propiedad de {{value}}",
|
||||
"VERIFICATION": "Ofrecemos dos métodos para validar manualmente tu dominio:",
|
||||
"VERIFICATION_HTML": "- HTTP. Coloca un fichero de verificación temporal en tu sitio web",
|
||||
"VERIFICATION_DNS": "- DNS. Crea una registro TXT en tu DNS",
|
||||
"VERIFICATION_DNS_DESC": "Si administras {{ value }} y tienes acceso a tus registros DNS, puedes crear un nuevo registro TXT con los siguientes valores:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Utiliza este código como valor para el registro TXT:",
|
||||
"VERIFICATION_HTTP_DESC": "Si tienes acceso al alojamiento de su sitio web, simplemente descarga el archivo de verificación y cárgalo en la URL proporcionada.",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "URL esperada:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Fichero de verificación:",
|
||||
"VERIFICATION_SKIP": "Puedes omitir la verificación por ahora y continuar creando tu organización, pero para poder usar este dominio debes completar este paso.",
|
||||
"VERIFICATION_VALIDATION_DESC": "No elimines el código de verificación, ya que ZITADEL volverá a comprobar la propiedad de tu dominio de vez en cuando.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Solicitar nuevo token",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Si quieres solicitar un nuevo token, selecciona tu método preferido. Si quieres validar un token persistente, haz clic en el botón de arriba.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Ya se ha solicitado un token de verificación. Haz clic en el botón para lanzar una comprobación de verificación.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Tipo de token:",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Si deseas solicitar un nuevo token, selecciona tu método preferido. Si desea validar un token persistente, haga clic en el botón de arriba.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Se ha seleccionado el método {{ value }} para verificar su dominio. Haz clic en el botón para forzar una verificación o restablecer el proceso de verificación.",
|
||||
"VERIFICATION_SUCCESSFUL": "¡Dominio verificado con éxito!",
|
||||
"REQUESTNEWTOKEN": "Solicitar nuevo token",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "Restablecer el método de verificación"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Descargar fichero",
|
||||
"SELECTORGTOOLTIP": "Seleccionar esta organización.",
|
||||
@ -1019,7 +1024,7 @@
|
||||
"DESCRIPTION": "Estas configuraciones amplían y sobrescriben tus configuraciones de instancia."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "General",
|
||||
"LANGUAGES": "Idiomas",
|
||||
"LOGIN": "Comportamiento del inicio de sesión y de la seguridad",
|
||||
"LOCKOUT": "Bloqueo",
|
||||
"COMPLEXITY": "Complejidad de contraseña",
|
||||
@ -1048,22 +1053,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Idioma por defecto",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Ajustes de idioma",
|
||||
"DEFAULT": "Idioma predeterminado",
|
||||
"ALLOWED": "Idiomas permitidos",
|
||||
"NOT_ALLOWED": "Idiomas no permitidos",
|
||||
"ALLOW_ALL": "Permitir todos los idiomas",
|
||||
"DISALLOW_ALL": "No permitir ningún idioma",
|
||||
"SETASDEFAULT": "Establecer como idioma predeterminado",
|
||||
"DEFAULT_SAVED": "Idioma predeterminado guardado",
|
||||
"ALLOWED_SAVED": "Idiomas permitidos guardados",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Ajustes SMTP",
|
||||
@ -1262,8 +1277,10 @@
|
||||
"RESET_DESCRIPTION": "Estás a punto de restaurar todos los valores por defecto. Todos los cambios que has hecho serán borrados permanentemente. ¿Estás seguro de que quieres continuar?",
|
||||
"UNSAVED_TITLE": "¿Continuar sin guardar?",
|
||||
"UNSAVED_DESCRIPTION": "Has hecho cambios sin guardar. ¿Quieres guardarlos ahora?",
|
||||
"LOCALE": "Código de idioma",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Has seleccionado un idioma que no está permitido. Puedes seguir modificando los textos. Pero si quieres que tus usuarios realmente puedan usar este idioma, cambia las restricciones de tus instancias.",
|
||||
"LANGUAGES_NOT_ALLOWED": "No permitido:",
|
||||
"LANGUAGE": "Idioma",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1374,7 +1391,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "La dirección del remitente SMTP coincide con el dominio de la instancia",
|
||||
"ALLOWUSERNAMEPASSWORD": "Nombre de usuario y contraseña permitido",
|
||||
"ALLOWEXTERNALIDP": "Permitido IDP externo",
|
||||
"ALLOWREGISTER": "Registro permitido",
|
||||
"ALLOWREGISTERUSERS": "Registro de usuarios permitido",
|
||||
"ALLOWREGISTERORGS": "Registro de organizaciones permitido",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "El inicio de sesión convencional con nombre de usuario y contraseña está permitido.",
|
||||
"ALLOWEXTERNALIDP_DESC": "El inicio de sesión está permitido para los proveedores de identidad subyacentes",
|
||||
"ALLOWREGISTER_DESC": "Si esta opción es seleccionada, aparece un paso adicional durante el inicio de sesión para registrar un usuario.",
|
||||
|
@ -871,14 +871,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "séquence",
|
||||
"CHECKBOX": "Filtrer par séquence",
|
||||
"SORT": "Triage",
|
||||
"ASC": "Ascendant",
|
||||
"DESC": "Descendant"
|
||||
"CHECKBOX": "Filtrer par séquence"
|
||||
},
|
||||
"SORT": "Triage",
|
||||
"ASC": "Ascendant",
|
||||
"DESC": "Descendant",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Date de création",
|
||||
"CHECKBOX": "Filtrer par date de création"
|
||||
"RADIO_FROM": "De",
|
||||
"RADIO_RANGE": "Gamme",
|
||||
"LABEL_SINCE": "Depuis",
|
||||
"LABEL_UNTIL": "Jusqu'à"
|
||||
},
|
||||
"OTHER": "autre",
|
||||
"OTHERS": "autres"
|
||||
@ -928,20 +930,22 @@
|
||||
"BTN": "Renommer"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Vérification de la propriété du domaine de l'organisation",
|
||||
"VERIFICATION": "Pour vérifier la propriété de votre domaine, vous devez télécharger un fichier de vérification et le charger à l'URL indiquée ci-dessous, ou placer une entrée DNS TXT Record pour l'URL indiquée. Pour terminer, cliquez sur le bouton de vérification.",
|
||||
"VERIFICATION_SKIP": "Vous pouvez ignorer la vérification pour l'instant et continuer à créer votre organisation, mais cette étape doit être terminée pour pouvoir utiliser votre organisation !",
|
||||
"VERIFICATION_VALIDATION_DESC": "Les jetons sont vérifiés régulièrement pour s'assurer que vous êtes toujours propriétaire du domaine.",
|
||||
"TITLE": "Vérifier la propriété de {{value}}",
|
||||
"VERIFICATION": "Nous vous proposons deux méthodes pour valider manuellement votre domaine :",
|
||||
"VERIFICATION_HTML": "-HTTP. Hébergez un fichier de vérification temporaire sur votre site Web",
|
||||
"VERIFICATION_DNS": "-DNS. Créer une entrée DNS d'enregistrement TXT",
|
||||
"VERIFICATION_DNS_DESC": "Si vous gérez {{ value }} et que vous avez accès à vos enregistrements DNS, vous pouvez créer un nouvel enregistrement TXT avec les valeurs suivantes :",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Utilisez ce code pour la valeur de l'enregistrement TXT :",
|
||||
"VERIFICATION_HTTP_DESC": "Si vous avez accès à l'hébergement de votre site Web, téléchargez simplement le fichier de vérification et téléchargez-le à l'URL fournie.",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "URL attendue :",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Dossier de vérification :",
|
||||
"VERIFICATION_SKIP": "Vous pouvez ignorer la vérification pour le moment et continuer à créer votre organisation, mais pour pouvoir utiliser votre domaine, cette étape doit être complétée !",
|
||||
"VERIFICATION_VALIDATION_DESC": "Ne supprimez pas le code de vérification, car ZITADEL revérifiera de temps en temps la propriété de votre domaine.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Demander un nouveau jeton",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Si vous voulez demander un nouveau jeton, sélectionnez votre méthode préférée. Si vous voulez valider un jeton persistant, cliquez sur le bouton ci-dessus.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Un jeton de vérification a déjà été demandé. Cliquez sur le bouton pour déclencher un contrôle de vérification.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Type de jeton",
|
||||
"VERIFICATION_SUCCESSFUL": "Domaine vérifié avec succès !",
|
||||
"REQUESTNEWTOKEN": "Demander un nouveau jeton",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"VERIFICATION_VALIDATION_ONGOING": "La méthode {{ value }} a été sélectionnée pour vérifier votre domaine. Cliquez sur le bouton pour déclencher une vérification ou réinitialiser le processus de vérification.",
|
||||
"VERIFICATION_SUCCESSFUL": "Domaine vérifié avec succès !",
|
||||
"RESETMETHOD": "Réinitialiser la méthode de vérification"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Télécharger le fichier",
|
||||
"SELECTORGTOOLTIP": "Sélectionnez cette organisation.",
|
||||
@ -1018,7 +1022,7 @@
|
||||
"DESCRIPTION": "Ces paramètres étendent et remplacent les paramètres de votre instance."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Général",
|
||||
"LANGUAGES": "Langues",
|
||||
"LOGIN": "Comportement de connexion et sécurité",
|
||||
"LOCKOUT": "Verrouillage",
|
||||
"COMPLEXITY": "Complexité du mot de passe",
|
||||
@ -1047,22 +1051,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Langue par défaut",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Paramètres de langue",
|
||||
"DEFAULT": "Langue par défaut",
|
||||
"ALLOWED": "Langues autorisées",
|
||||
"NOT_ALLOWED": "Langues non autorisées",
|
||||
"ALLOW_ALL": "Autoriser toutes les langues",
|
||||
"DISALLOW_ALL": "Interdire toutes les langues",
|
||||
"SETASDEFAULT": "Définir comme langue par défaut",
|
||||
"DEFAULT_SAVED": "Langue par défaut enregistrée",
|
||||
"ALLOWED_SAVED": "Langues autorisées enregistrées",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Paramètres SMTP",
|
||||
@ -1261,8 +1275,10 @@
|
||||
"RESET_DESCRIPTION": "Vous êtes sur le point de restaurer toutes les valeurs par défaut. Toutes les modifications que vous avez apportées seront définitivement supprimées. Voulez-vous vraiment continuer ?",
|
||||
"UNSAVED_TITLE": "Continuer sans sauvegarder ?",
|
||||
"UNSAVED_DESCRIPTION": "Vous avez apporté des modifications sans les sauvegarder. Voulez-vous les enregistrer maintenant ?",
|
||||
"LOCALE": "Code Locale",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Vous avez sélectionné une langue qui n'est pas autorisée. Vous pouvez continuer à modifier les textes. Mais si vous voulez que vos utilisateurs puissent réellement utiliser cette langue, modifiez les restrictions de vos instances.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Non autorisé:",
|
||||
"LANGUAGE": "Langue",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1373,7 +1389,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "L'adresse de l'expéditeur SMTP correspond au domaine de l'instance",
|
||||
"ALLOWUSERNAMEPASSWORD": "Nom d'utilisateur Mot de passe autorisé",
|
||||
"ALLOWEXTERNALIDP": "IDP externe autorisé",
|
||||
"ALLOWREGISTER": "Enregistrement autorisé",
|
||||
"ALLOWREGISTERUSERS": "Enregistrer les utilisateurs autorisés",
|
||||
"ALLOWREGISTERORGS": "Enregistrer les organisations autorisées",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "La connexion classique avec nom d'utilisateur et mot de passe est autorisée.",
|
||||
"ALLOWEXTERNALIDP_DESC": "La connexion est autorisée pour les fournisseurs d'identité sous-jacents",
|
||||
"ALLOWREGISTER_DESC": "Si l'option est sélectionnée, une étape supplémentaire pour l'enregistrement d'un utilisateur apparaît dans la connexion.",
|
||||
|
@ -870,14 +870,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Sequence",
|
||||
"CHECKBOX": "Filter per sequenza",
|
||||
"SORT": "",
|
||||
"ASC": "Ascending",
|
||||
"DESC": "Descending"
|
||||
"CHECKBOX": "Filter per sequenza"
|
||||
},
|
||||
"SORT": "Ordina per",
|
||||
"ASC": "Ascendente",
|
||||
"DESC": "Discendente",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Creation Date",
|
||||
"CHECKBOX": "Filter by Creation Date"
|
||||
"RADIO_FROM": "Da",
|
||||
"RADIO_RANGE": "Intervallo",
|
||||
"LABEL_SINCE": "Da",
|
||||
"LABEL_UNTIL": "A"
|
||||
},
|
||||
"OTHER": "altro",
|
||||
"OTHERS": "altri"
|
||||
@ -928,20 +930,22 @@
|
||||
"BTN": "Rinomina"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Verificazione della propriet\u00e0 del dominio dell'organizzazione",
|
||||
"VERIFICATION": "Verifica la propriet\u00e0 del tuo dominio. \u00c8 necessario scaricare un file di verifica e caricarlo all'URL fornito elencato di seguito, o inserire una voce DNS TXT Record per l'URL fornito. Per completare, clicca sul pulsante di verifica.",
|
||||
"VERIFICATION_SKIP": "Puoi saltare la verifica per ora e continuare a creare la tua organizzazione, ma per usare la tua organizzazione questo passo deve essere completato!",
|
||||
"VERIFICATION_VALIDATION_DESC": "I token sono controllati regolarmente per assicurarsi che tu sia ancora proprietario del dominio.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Richiesta di un nuovo token",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Se vuoi richiedere un nuovo token, seleziona il tuo metodo preferito. Se vuoi convalidare un token persistente, clicca sul pulsante qui sopra.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "\u00c8 gi\u00e0 stato richiesto un token di verifica. Clicca sul pulsante per richiedere un altro controllo di verifica.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Tipo di token:",
|
||||
"TITLE": "Verifica la proprietà di {{value}}",
|
||||
"VERIFICATION": "Ti offriamo due metodi per convalidare manualmente il tuo dominio:",
|
||||
"VERIFICATION_HTML": "-HTTP. Ospita un file di verifica temporaneo sul tuo sito web",
|
||||
"VERIFICATION_DNS": "-DNS. Crea una voce DNS del record TXT",
|
||||
"VERIFICATION_DNS_DESC": "Se gestisci {{ value }} e hai accesso ai tuoi record DNS, puoi creare un nuovo record TXT con i seguenti valori:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Ospite:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Utilizza questo codice per il valore del record TXT:",
|
||||
"VERIFICATION_HTTP_DESC": "Se hai accesso all'hosting del tuo sito web, scarica semplicemente il file di verifica e caricalo all'URL fornito",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "URL previsto:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "File di verifica:",
|
||||
"VERIFICATION_SKIP": "Per ora puoi saltare la verifica e continuare a creare la tua organizzazione, ma per poter utilizzare il tuo dominio è necessario completare questo passaggio!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Non eliminare il codice di verifica, poiché ZITADEL ricontrollerà di tanto in tanto la proprietà del tuo dominio.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Richiedi nuovo token",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Il metodo {{ value }} è stato selezionato per verificare il tuo dominio. Fare clic sul pulsante per attivare un controllo di verifica o reimpostare il processo di verifica.",
|
||||
"VERIFICATION_SUCCESSFUL": "Dominio verificato con successo!",
|
||||
"REQUESTNEWTOKEN": "Richiedi un nuovo token",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "Reimposta il metodo di verifica"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Scaricare il file",
|
||||
"SELECTORGTOOLTIP": "Seleziona questa organizzazione.",
|
||||
@ -1018,7 +1022,7 @@
|
||||
"DESCRIPTION": "Queste impostazioni si applicheranno alla organizzazione corrente."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Generale",
|
||||
"LANGUAGES": "Lingue",
|
||||
"LOGIN": "Comportamento login e sicurezza",
|
||||
"LOCKOUT": "Meccanismi di bloccaggio",
|
||||
"COMPLEXITY": "Complessità della password",
|
||||
@ -1047,22 +1051,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Lingua standard",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Impostazioni della lingua",
|
||||
"DEFAULT": "Lingua predefinita",
|
||||
"ALLOWED": "Lingue consentite",
|
||||
"NOT_ALLOWED": "Lingue non consentite",
|
||||
"ALLOW_ALL": "Consenti tutte le lingue",
|
||||
"DISALLOW_ALL": "Non consentire tutte le lingue",
|
||||
"SETASDEFAULT": "Imposta come lingua predefinita",
|
||||
"DEFAULT_SAVED": "Lingua predefinita salvata",
|
||||
"ALLOWED_SAVED": "Lingue consentite salvate",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Impostazioni SMTP",
|
||||
@ -1261,8 +1275,10 @@
|
||||
"RESET_DESCRIPTION": "Stai per ripristinare tutti i valori predefiniti. Tutte le modifiche che hai fatto saranno cancellate in modo permanente. Vuoi davvero continuare?",
|
||||
"UNSAVED_TITLE": "Continuare senza salvare?",
|
||||
"UNSAVED_DESCRIPTION": "Hai fatto delle modifiche senza salvare. Vuoi salvare ora?",
|
||||
"LOCALE": "Codice locale",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Hai selezionato una lingua non consentita. Puoi continuare a modificare i testi. Ma se vuoi che i tuoi utenti possano effettivamente utilizzare questa lingua, cambia le restrizioni delle tue istanze.",
|
||||
"LANGUAGE": "Lingua",
|
||||
"LANGUAGES_NOT_ALLOWED": "Non consentito:",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1373,7 +1389,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "L'indirizzo mittente SMTP corrisponde al dominio dell'istanza",
|
||||
"ALLOWUSERNAMEPASSWORD": "Autenticazione classica con password consentita",
|
||||
"ALLOWEXTERNALIDP": "IDP esterno consentito",
|
||||
"ALLOWREGISTER": "Registrazione consentita",
|
||||
"ALLOWREGISTERUSERS": "Registrazione utenti consentita",
|
||||
"ALLOWREGISTERORGS": "Registrazione organizzazioni consentita",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "Autenticazione classica con nome utente e password \u00e8 permessa.",
|
||||
"ALLOWEXTERNALIDP_DESC": "Il login \u00e8 permesso per gli IDP sottostanti",
|
||||
"ALLOWREGISTER_DESC": "Se l'opzione \u00e8 selezionata, nel login apparirà un passo aggiuntivo per la registrazione di un utente.",
|
||||
|
@ -872,14 +872,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "シーケンス",
|
||||
"CHECKBOX": "シーケンスで絞り込み",
|
||||
"SORT": "ソート",
|
||||
"ASC": "昇順",
|
||||
"DESC": "降順"
|
||||
"CHECKBOX": "シーケンスで絞り込み"
|
||||
},
|
||||
"SORT": "ソート",
|
||||
"ASC": "昇順",
|
||||
"DESC": "降順",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "作成日",
|
||||
"CHECKBOX": "作成日で絞り込み"
|
||||
"RADIO_FROM": "から",
|
||||
"RADIO_RANGE": "範囲",
|
||||
"LABEL_SINCE": "以降",
|
||||
"LABEL_UNTIL": "まで"
|
||||
},
|
||||
"OTHER": "その他",
|
||||
"OTHERS": "その他"
|
||||
@ -929,20 +931,22 @@
|
||||
"BTN": "名前の変更"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "組織ドメインの所有権の認証",
|
||||
"VERIFICATION": "ドメインの所有権を確認するには、検証ファイルをダウンロードし、下記の提供されたURLにアップロードするか、提供されたURLのTXTレコードのDNSエントリーを配置する必要があります。完了するには、検証するボタンをクリックしてください。",
|
||||
"VERIFICATION_SKIP": "認証をスキップしたまま組織を作成することはできますが、組織を使用するにはこのステップを完了する必要があります。",
|
||||
"VERIFICATION_VALIDATION_DESC": "ユーザーがドメインの所有者であることを確認するために、トークンは定期的にチェックされます。",
|
||||
"TITLE": "{{value}} の所有権を確認します",
|
||||
"VERIFICATION": "ドメインを手動で検証する 2 つの方法が提供されています。",
|
||||
"VERIFICATION_HTML": "- HTTP。 Web サイト上で一時検証ファイルをホストする",
|
||||
"VERIFICATION_DNS": "-DNS。 TXT レコードの DNS エントリを作成する",
|
||||
"VERIFICATION_DNS_DESC": "{{ value }} を管理しており、DNS レコードにアクセスできる場合は、次の値を使用して新しい TXT レコードを作成できます。",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "TXT レコードの値には次のコードを使用します。",
|
||||
"VERIFICATION_HTTP_DESC": "Web サイトのホスティングにアクセスできる場合は、検証ファイルをダウンロードし、指定された URL にアップロードするだけです。",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "予想される URL:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "検証ファイル:",
|
||||
"VERIFICATION_SKIP": "現時点では検証をスキップして組織の作成を続行できますが、ドメインを使用するにはこの手順を完了する必要があります。",
|
||||
"VERIFICATION_VALIDATION_DESC": "ZITADEL はドメインの所有権を随時再確認するため、確認コードは削除しないでください。",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "新しいトークンをリクエストする",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "新しいトークンをリクエストする場合は、方法を選択します。永続的なトークンを認証する場合は、上のボタンをクリックします。",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "認証トークンはすでにリクエストされています。ボタンをクリックして、認証チェックをトリガーする。",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "トークンのタイプ:",
|
||||
"VERIFICATION_SUCCESSFUL": "ドメインは正常に認証されました!",
|
||||
"REQUESTNEWTOKEN": "新しいトークンをリクエストする",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"VERIFICATION_VALIDATION_ONGOING": "ドメインを確認するために {{ value }} 方法が選択されました。ボタンをクリックして検証チェックをトリガーするか、検証プロセスをリセットします。",
|
||||
"VERIFICATION_SUCCESSFUL": "ドメインが正常に認証されました。",
|
||||
"RESETMETHOD": "リセット確認方法"
|
||||
},
|
||||
"DOWNLOAD_FILE": "ファイルをダウンロード",
|
||||
"SELECTORGTOOLTIP": "この組織を選択",
|
||||
@ -1019,7 +1023,7 @@
|
||||
"DESCRIPTION": "これらの設定は、インスタンス設定を拡張・上書きします。"
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "全般",
|
||||
"LANGUAGES": "一般設定",
|
||||
"LOGIN": "ログイン動作とセキュリティ",
|
||||
"LOCKOUT": "ロックアウト",
|
||||
"COMPLEXITY": "パスワードの複雑さ",
|
||||
@ -1048,22 +1052,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "デフォルトの言語",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "言語設定",
|
||||
"DEFAULT": "デフォルト言語",
|
||||
"ALLOWED": "許可された言語",
|
||||
"NOT_ALLOWED": "許可されていない言語",
|
||||
"ALLOW_ALL": "すべての言語を許可する",
|
||||
"DISALLOW_ALL": "すべての言語を許可しない",
|
||||
"SETASDEFAULT": "デフォルト言語として設定する",
|
||||
"DEFAULT_SAVED": "デフォルト言語が保存されました",
|
||||
"ALLOWED_SAVED": "許可された言語が保存されました",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP設定",
|
||||
@ -1257,8 +1271,10 @@
|
||||
"RESET_DESCRIPTION": "すべてのデフォルト値を復元しようとしています。ユーザーが行ったすべての変更は完全に削除されます。本当によろしいですか?",
|
||||
"UNSAVED_TITLE": "保存せずに続行しますか?",
|
||||
"UNSAVED_DESCRIPTION": "あなたは保存せずに変更を加えました。今すぐ保存しますか?",
|
||||
"LOCALE": "ロケールコード",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "許可されていない言語を選択しました。テキストを変更し続けることはできますが、実際にこの言語を使用できるようにするには、インスタンスの制限を変更してください。",
|
||||
"LANGUAGES_NOT_ALLOWED": "許可されていない言語:",
|
||||
"LANGUAGE": "言語",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1369,7 +1385,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP送信者アドレスはインスタンスドメインに一致しています",
|
||||
"ALLOWUSERNAMEPASSWORD": "ユーザー名とパスワードを許可",
|
||||
"ALLOWEXTERNALIDP": "外部IDPを許可",
|
||||
"ALLOWREGISTER": "登録を許可",
|
||||
"ALLOWREGISTERUSERS": "ユーザーの登録を許可",
|
||||
"ALLOWREGISTERORGS": "組織の登録を許可",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "ユーザー名とパスワードを使用した従来のログインを許可します。",
|
||||
"ALLOWEXTERNALIDP_DESC": "基礎となるIDプロバイダーにログインを許可します。",
|
||||
"ALLOWREGISTER_DESC": "このオプションが選択されている場合、ユーザーを登録するための追加のステップがログインに表示されます。",
|
||||
|
@ -872,14 +872,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Секвенца",
|
||||
"CHECKBOX": "Филтер според секвенцата",
|
||||
"SORT": "Сортирање",
|
||||
"ASC": "Растечки",
|
||||
"DESC": "Опаѓачки"
|
||||
"CHECKBOX": "Филтер според секвенцата"
|
||||
},
|
||||
"SORT": "Сортирање",
|
||||
"ASC": "Растечки",
|
||||
"DESC": "Опаѓачки",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Датум на креирање",
|
||||
"CHECKBOX": "Филтер според датумот на креирање"
|
||||
"RADIO_FROM": "Од",
|
||||
"RADIO_RANGE": "Ранг",
|
||||
"LABEL_SINCE": "Од",
|
||||
"LABEL_UNTIL": "До"
|
||||
},
|
||||
"OTHER": "друго",
|
||||
"OTHERS": "други"
|
||||
@ -929,20 +931,22 @@
|
||||
"BTN": "Преименувај"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Потврда за сопственост на доменот на организацијата",
|
||||
"VERIFICATION": "За да ја потврдите сопственоста на вашиот домен, треба да преземете датотека за потврда и да ја прикачите на препратената URL адреса наведена подолу, или да поставите запис на DNS (TXT Record) за препратената URL адреса. За да завршите, кликнете на копчето за верификација.",
|
||||
"VERIFICATION_SKIP": "Можете да ја прескокнете верификацијата за сега и да продолжите со креирањето на вашата организација, но за да ја користите вашата организација, овој чекор треба да се заврши!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Токените редовно се проверуваат за да се осигура дека сѐ уште сте сопственик на доменот.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Побарај нов токен",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Ако сакате да побарате нов токен, изберете ја вашата посакувана метода. Ако сакате да валидирате веќе постоечки токен, кликнете на копчето погоре.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Веќе е баран верификациски токен. Кликнете на копчето за да покренете проверка на верификацијата.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Тип на токенот:",
|
||||
"VERIFICATION_SUCCESSFUL": "Доменот е успешно верифициран!",
|
||||
"REQUESTNEWTOKEN": "Побарај нов токен",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"TITLE": "Потврдете ја сопственоста на {{value}}",
|
||||
"VERIFICATION": "Ви нудиме два методи за рачно потврдување на вашиот домен:",
|
||||
"VERIFICATION_HTML": "- HTTP. Поставете привремена датотека за потврда на вашата веб-локација",
|
||||
"VERIFICATION_DNS": "- DNS. Креирајте запис за DNS за снимање TXT",
|
||||
"VERIFICATION_DNS_DESC": "Ако управувате со {{ вредност }} и имате пристап до вашите записи DNS, можете да креирате нов TXT запис со следните вредности:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Користете го овој код за вредноста на записот TXT:",
|
||||
"VERIFICATION_HTTP_DESC": "Ако имате пристап до хостирањето на вашата веб-локација, едноставно преземете ја датотеката за верификација и поставете ја на дадената URL адреса",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "Очекувана URL адреса:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Датотека за верификација:",
|
||||
"VERIFICATION_SKIP": "Засега можете да ја прескокнете потврдата и да продолжите да ја креирате вашата организација, но за да го користите вашиот домен, овој чекор треба да се заврши!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Не бришете го кодот за потврда, бидејќи ZITADEL одвреме-навреме повторно ќе ја проверува сопственоста на вашиот домен.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Побарајте нов токен",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Методот {{ вредност }} е избран за да се потврди вашиот домен. Кликнете на копчето за да активирате проверка за верификација или да го ресетирате процесот на верификација.",
|
||||
"VERIFICATION_SUCCESSFUL": "Доменот е успешно потврден!",
|
||||
"RESETMETHOD": "Ресетирај го методот за верификација"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Преземи датотека",
|
||||
"SELECTORGTOOLTIP": "Изберете ја оваа организација.",
|
||||
@ -1020,7 +1024,7 @@
|
||||
"DESCRIPTION": "Овие подесувања ги прошируваат и препишуваат подесувањата на вашата инстанца."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Генерални",
|
||||
"LANGUAGES": "Општо",
|
||||
"LOGIN": "Правила и безбедност при најава",
|
||||
"LOCKOUT": "Забрана на пристап",
|
||||
"COMPLEXITY": "Сложеност на лозинката",
|
||||
@ -1049,22 +1053,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Стандарден јазик",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Подесувања за јазик",
|
||||
"DEFAULT": "Стандарден јазик",
|
||||
"ALLOWED": "Дозволени јазици",
|
||||
"NOT_ALLOWED": "Не дозволени јазици",
|
||||
"ALLOW_ALL": "Дозволи ги сите јазици",
|
||||
"DISALLOW_ALL": "Забрани ги сите јазици",
|
||||
"SETASDEFAULT": "Постави како стандарден јазик",
|
||||
"DEFAULT_SAVED": "Стандардниот јазик е зачуван",
|
||||
"ALLOWED_SAVED": "Дозволените јазици се зачувани",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP подесувања",
|
||||
@ -1263,8 +1277,10 @@
|
||||
"RESET_DESCRIPTION": "Се подготвувате да ги вратите сите стандардни вредности. Сите промени што ги направивте ќе бидат трајно избришани. Дали сте сигурни дека сакате да продолжите?",
|
||||
"UNSAVED_TITLE": "Дали сакате да продолжите без зачувување?",
|
||||
"UNSAVED_DESCRIPTION": "Имате направено промени без зачувување. Дали сакате да ги зачувате сега?",
|
||||
"LOCALE": "Locale Code",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Избравте јазик кој не е дозволен. Можете да продолжите да ги менувате текстовите. Но, ако сакате вашите корисници да можат да го користат овој јазик, променете ги ограничувањата на вашата инстанца.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Не е дозволено:",
|
||||
"LANGUAGE": "Јазик",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1375,7 +1391,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP адресата на испраќачот се поклопува со доменот на инстанцата",
|
||||
"ALLOWUSERNAMEPASSWORD": "Дозволено корисничко име и лозинка",
|
||||
"ALLOWEXTERNALIDP": "Дозволен надворешен IDP",
|
||||
"ALLOWREGISTER": "Дозволена регистрација",
|
||||
"ALLOWREGISTERUSERS": "Дозволена регистрација на корисници",
|
||||
"ALLOWREGISTERORGS": "Дозволена регистрација на организации",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "Дозволена е конвенционална најава со корисничко име и лозинка.",
|
||||
"ALLOWEXTERNALIDP_DESC": "Најавата е дозволена за поддржуваните IDPs",
|
||||
"ALLOWREGISTER_DESC": "Доколку е избрана опцијата, се прикажува дополнителен чекор за регистрирање на корисник во најавата.",
|
||||
|
@ -872,14 +872,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Reeks",
|
||||
"CHECKBOX": "Filter op Reeks",
|
||||
"SORT": "Sortering",
|
||||
"ASC": "Oplopend",
|
||||
"DESC": "Aflopend"
|
||||
"CHECKBOX": "Filter op Reeks"
|
||||
},
|
||||
"SORT": "Sortering",
|
||||
"ASC": "Oplopend",
|
||||
"DESC": "Aflopend",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Aanmaakdatum",
|
||||
"CHECKBOX": "Filter op Aanmaakdatum"
|
||||
"RADIO_FROM": "Van",
|
||||
"RADIO_RANGE": "Reeks",
|
||||
"LABEL_SINCE": "Sinds",
|
||||
"LABEL_UNTIL": "Tot"
|
||||
},
|
||||
"OTHER": "ander",
|
||||
"OTHERS": "anderen"
|
||||
@ -929,20 +931,22 @@
|
||||
"BTN": "Hernoemen"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Verificatie van Organisatie Domein Eigendom",
|
||||
"VERIFICATION": "Om het eigendom van uw domein te verifiëren, moet u een verificatiebestand downloaden en uploaden op de hieronder vermelde URL, of een TXT Record DNS-invoer plaatsen voor de verstrekte URL. Om te voltooien, klik op de knop om te verifiëren.",
|
||||
"VERIFICATION_SKIP": "Je kunt de verificatie nu overslaan en doorgaan met het aanmaken van je organisatie, maar om je organisatie te kunnen gebruiken, moet deze stap worden voltooid!",
|
||||
"VERIFICATION_VALIDATION_DESC": "De tokens worden regelmatig gecontroleerd om te zorgen dat u nog steeds eigenaar bent van het domein.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Vraag nieuw token aan",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Als u een nieuw token wilt aanvragen, selecteer dan uw voorkeursmethode. Als u een bestaand token wilt valideren, klik dan op de knop hierboven.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Er is al een verificatietoken aangevraagd. Klik op de knop om een verificatiecontrole te activeren.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Type van het token:",
|
||||
"TITLE": "Verifieer het eigendom van {{value}}",
|
||||
"VERIFICATION": "Wij bieden u twee methoden aan om uw domein handmatig te valideren:",
|
||||
"VERIFICATION_HTML": "-HTTP. Host een tijdelijk verificatiebestand op uw website",
|
||||
"VERIFICATION_DNS": "- DNS. Maak een TXT Record DNS-vermelding",
|
||||
"VERIFICATION_DNS_DESC": "Als u {{ value }} beheert en toegang heeft tot uw DNS-records, kunt u een nieuw TXT-record maken met de volgende waarden:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Gebruik deze code voor de waarde van het TXT-record:",
|
||||
"VERIFICATION_HTTP_DESC": "Als u toegang heeft tot de hosting van uw website, downloadt u eenvoudigweg het verificatiebestand en uploadt u dit naar de opgegeven URL",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "Verwachte URL:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Verificatiebestand:",
|
||||
"VERIFICATION_SKIP": "U kunt de verificatie voorlopig overslaan en doorgaan met het aanmaken van uw organisatie, maar om uw domein te gebruiken moet deze stap worden voltooid!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Verwijder de verificatiecode niet, aangezien ZITADEL van tijd tot tijd het eigendom van uw domein opnieuw zal controleren.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Vraag een nieuw token aan",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "De methode {{ value }} is geselecteerd om uw domein te verifiëren. Klik op de knop om een verificatiecontrole te activeren of het verificatieproces opnieuw in te stellen.",
|
||||
"VERIFICATION_SUCCESSFUL": "Domein succesvol geverifieerd!",
|
||||
"REQUESTNEWTOKEN": "Vraag nieuw token aan",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "Verificatiemethode opnieuw instellen"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Download bestand",
|
||||
"SELECTORGTOOLTIP": "Selecteer deze organisatie.",
|
||||
@ -1019,7 +1023,7 @@
|
||||
"DESCRIPTION": "Deze instellingen breiden uw instantie instellingen uit en overschrijven deze."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Algemeen",
|
||||
"LANGUAGES": "Talen",
|
||||
"LOGIN": "Login Gedrag en Beveiliging",
|
||||
"LOCKOUT": "Lockout",
|
||||
"COMPLEXITY": "Wachtwoord complexiteit",
|
||||
@ -1048,22 +1052,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Standaard Taal",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "Engels",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portugees",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Taalinstellingen",
|
||||
"DEFAULT": "Standaardtaal",
|
||||
"ALLOWED": "Toegestane Talen",
|
||||
"NOT_ALLOWED": "Niet Toegestane Talen",
|
||||
"ALLOW_ALL": "Sta alle talen toe",
|
||||
"DISALLOW_ALL": "Sta geen talen toe",
|
||||
"SETASDEFAULT": "Stel in als standaardtaal",
|
||||
"DEFAULT_SAVED": "Standaardtaal opgeslagen",
|
||||
"ALLOWED_SAVED": "Toegestane talen opgeslagen",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "Engels",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portugees",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP Instellingen",
|
||||
@ -1261,9 +1275,11 @@
|
||||
"RESET_TITLE": "Herstel Standaard Waarden",
|
||||
"RESET_DESCRIPTION": "U staat op het punt om alle standaardwaarden te herstellen. Alle wijzigingen die u heeft gemaakt zullen permanent worden verwijderd. Weet u zeker dat u wilt doorgaan?",
|
||||
"UNSAVED_TITLE": "Doorgaan zonder opslaan?",
|
||||
"UNSAAVED_DESCRIPTION": "U heeft wijzigingen gemaakt zonder op te slaan. Wilt u nu opslaan?",
|
||||
"LOCALE": "Locale Code",
|
||||
"LOCALES": {
|
||||
"UNSAVED_DESCRIPTION": "U heeft wijzigingen gemaakt zonder op te slaan. Wilt u nu opslaan?",
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "U heeft een taal geselecteerd die niet is toegestaan. U kunt doorgaan met het wijzigen van de teksten. Maar als u wilt dat uw gebruikers deze taal daadwerkelijk kunnen gebruiken, wijzig dan de beperkingen van uw instantie.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Niet toegestaan:",
|
||||
"LANGUAGE": "Taal",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1374,7 +1390,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP Afzender Adres komt overeen met Instantie Domein",
|
||||
"ALLOWUSERNAMEPASSWORD": "Gebruikersnaam Wachtwoord toegestaan",
|
||||
"ALLOWEXTERNALIDP": "Externe IDP toegestaan",
|
||||
"ALLOWREGISTER": "Registratie toegestaan",
|
||||
"ALLOWREGISTERUSERS": "Gebruikersregistratie toegestaan",
|
||||
"ALLOWREGISTERORGS": "Organisatieregistratie toegestaan",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "De conventionele login met gebruikersnaam en wachtwoord is toegestaan.",
|
||||
"ALLOWEXTERNALIDP_DESC": "De login is toegestaan voor de onderliggende identiteitsproviders",
|
||||
"ALLOWREGISTER_DESC": "Als de optie is geselecteerd, verschijnt er een extra stap voor het registreren van een gebruiker in het login proces.",
|
||||
|
@ -871,14 +871,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Sekwencja",
|
||||
"CHECKBOX": "Filtruj według sekwencji",
|
||||
"SORT": "Sortowanie",
|
||||
"ASC": "Rosnące",
|
||||
"DESC": "Malejące"
|
||||
"CHECKBOX": "Filtruj według sekwencji"
|
||||
},
|
||||
"SORT": "Sortowanie",
|
||||
"ASC": "Rosnące",
|
||||
"DESC": "Malejące",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Data utworzenia",
|
||||
"CHECKBOX": "Filtruj według daty utworzenia"
|
||||
"RADIO_FROM": "Od",
|
||||
"RADIO_RANGE": "Zakres",
|
||||
"LABEL_SINCE": "Od",
|
||||
"LABEL_UNTIL": "Do"
|
||||
},
|
||||
"OTHER": "inne",
|
||||
"OTHERS": "inni"
|
||||
@ -928,20 +930,22 @@
|
||||
"BTN": "Zmień nazwę"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Weryfikacja własności domeny organizacji",
|
||||
"VERIFICATION": "Aby zweryfikować własność swojej domeny, musisz pobrać plik weryfikacyjny i przesłać go na podany poniżej adres URL lub dodać rekord TXT DNS dla podanego adresu URL. Aby zakończyć, kliknij przycisk weryfikuj.",
|
||||
"VERIFICATION_SKIP": "Możesz teraz pominąć weryfikację i kontynuować tworzenie swojej organizacji, ale aby korzystać z organizacji, ta krok musi zostać ukończony!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Tokeny są regularnie sprawdzane, aby upewnić się, że nadal jesteś właścicielem domeny.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Prośba o nowy token",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Jeśli chcesz poprosić o nowy token, wybierz preferowany sposób. Jeśli chcesz zwalidować trwający token, kliknij powyższy przycisk.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Token weryfikacyjny został już zażądany. Kliknij przycisk, aby uruchomić sprawdzenie weryfikacyjne.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Typ tokenu:",
|
||||
"VERIFICATION_SUCCESSFUL": "Domena zweryfikowana pomyślnie!",
|
||||
"REQUESTNEWTOKEN": "Poproś o nowy token",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"TITLE": "Zweryfikuj własność {{value}}",
|
||||
"VERIFICATION": "Oferujemy dwie metody ręcznej weryfikacji domeny:",
|
||||
"VERIFICATION_HTML": "-HTTP. Umieść tymczasowy plik weryfikacyjny w swojej witrynie",
|
||||
"VERIFICATION_DNS": "-DNS. Utwórz wpis DNS rekordu TXT",
|
||||
"VERIFICATION_DNS_DESC": "Jeśli zarządzasz wartością {{ value }} i masz dostęp do swoich rekordów DNS, możesz utworzyć nowy rekord TXT z następującymi wartościami:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Użyj tego kodu dla wartości rekordu TXT:",
|
||||
"VERIFICATION_HTTP_DESC": "Jeśli masz dostęp do hostingu swojej witryny, po prostu pobierz plik weryfikacyjny i prześlij go pod podanym adresem URL",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "Oczekiwany adres URL:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Plik weryfikacyjny:",
|
||||
"VERIFICATION_SKIP": "Możesz na razie pominąć weryfikację i kontynuować tworzenie organizacji, jednak aby móc korzystać z domeny, ten krok musi zostać ukończony!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Nie usuwaj kodu weryfikacyjnego, ponieważ ZITADEL będzie od czasu do czasu ponownie sprawdzał własność Twojej domeny.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Poproś o nowy token",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Wybrano metodę {{ value }} do weryfikacji Twojej domeny. Kliknij przycisk, aby uruchomić kontrolę weryfikacyjną lub zresetować proces weryfikacji.",
|
||||
"VERIFICATION_SUCCESSFUL": "Domena pomyślnie zweryfikowana!",
|
||||
"RESETMETHOD": "Zresetuj metodę weryfikacji"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Pobierz plik",
|
||||
"SELECTORGTOOLTIP": "Wybierz tę organizację.",
|
||||
@ -1018,7 +1022,7 @@
|
||||
"DESCRIPTION": "Te ustawienia rozszerzają i nadpisują ustawienia instancji."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Ogólne",
|
||||
"LANGUAGES": "Języki",
|
||||
"LOGIN": "Zachowanie logowania i bezpieczeństwo",
|
||||
"LOCKOUT": "Blokada",
|
||||
"COMPLEXITY": "Złożoność hasła",
|
||||
@ -1047,22 +1051,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Domyślny język",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Ustawienia językowe",
|
||||
"DEFAULT": "Domyślny język",
|
||||
"ALLOWED": "Dozwolone języki",
|
||||
"NOT_ALLOWED": "Niedozwolone języki",
|
||||
"ALLOW_ALL": "Zezwól na wszystkie języki",
|
||||
"DISALLOW_ALL": "Zabroń wszystkich języków",
|
||||
"SETASDEFAULT": "Ustaw jako domyślny język",
|
||||
"DEFAULT_SAVED": "Domyślny język zapisany",
|
||||
"ALLOWED_SAVED": "Dozwolone języki zapisane",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Ustawienia SMTP",
|
||||
@ -1261,8 +1275,10 @@
|
||||
"RESET_DESCRIPTION": "Masz zamiar przywrócić domyślne linki dla TOS i polityki prywatności. Czy na pewno chcesz kontynuować?",
|
||||
"UNSAVED_TITLE": "Kontynuuj bez zapisywania?",
|
||||
"UNSAVED_DESCRIPTION": "Wprowadziłeś zmiany bez zapisywania. Czy chcesz zapisać teraz?",
|
||||
"LOCALE": "Kod Języka",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Wybrałeś język, który nie jest dozwolony. Możesz kontynuować modyfikowanie tekstów. Ale jeśli chcesz, aby twoi użytkownicy mogli faktycznie używać tego języka, zmień ograniczenia swoich instancji.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Niedozwolone:",
|
||||
"LANGUAGE": "Język",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1373,7 +1389,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "Adres nadawcy SMTP pasuje do domeny instancji",
|
||||
"ALLOWUSERNAMEPASSWORD": "Zezwól na użycie nazwy użytkownika i hasła",
|
||||
"ALLOWEXTERNALIDP": "Zezwól na zewnętrznego dostawcę tożsamości",
|
||||
"ALLOWREGISTER": "Zezwól na rejestrację",
|
||||
"ALLOWREGISTERUSERS": "Zezwól na rejestrację użytkowników",
|
||||
"ALLOWREGISTERORGS": "Zezwól na rejestrację organizacji",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "Zwykłe logowanie za pomocą nazwy użytkownika i hasła jest dozwolone.",
|
||||
"ALLOWEXTERNALIDP_DESC": "Logowanie jest dozwolone dla dostawców tożsamości podstawowych",
|
||||
"ALLOWREGISTER_DESC": "Jeśli ta opcja jest zaznaczona, pojawi się dodatkowy krok rejestracji użytkownika w procesie logowania.",
|
||||
|
@ -872,14 +872,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Sequência",
|
||||
"CHECKBOX": "Filtrar por Sequência",
|
||||
"SORT": "Ordenação",
|
||||
"ASC": "Crescente",
|
||||
"DESC": "Decrescente"
|
||||
"CHECKBOX": "Filtrar por Sequência"
|
||||
},
|
||||
"SORT": "Ordenação",
|
||||
"ASC": "Crescente",
|
||||
"DESC": "Decrescente",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Data de Criação",
|
||||
"CHECKBOX": "Filtrar por Data de Criação"
|
||||
"RADIO_FROM": "Desde",
|
||||
"RADIO_RANGE": "Intervalo",
|
||||
"LABEL_SINCE": "Desde",
|
||||
"LABEL_UNTIL": "Até"
|
||||
},
|
||||
"OTHER": "outro",
|
||||
"OTHERS": "outros"
|
||||
@ -929,20 +931,22 @@
|
||||
"BTN": "Renomear"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Verificação de Propriedade do Domínio da Organização",
|
||||
"VERIFICATION": "Para verificar a propriedade do seu domínio, você precisa baixar um arquivo de verificação e enviá-lo para a URL fornecida abaixo, ou criar um registro DNS TXT para a URL fornecida. Para concluir, clique no botão para verificar.",
|
||||
"VERIFICATION_SKIP": "Você pode pular a verificação por enquanto e continuar a criar sua organização, mas para usar sua organização, esta etapa deve ser concluída!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Os tokens são verificados regularmente para garantir que você ainda seja o proprietário do domínio.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Solicitar Novo Token",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Se você deseja solicitar um novo token, selecione seu método preferido. Se você deseja validar um token persistente, clique no botão acima.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Um token de verificação já foi solicitado. Clique no botão para iniciar uma verificação.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Tipo do token:",
|
||||
"TITLE": "Verifique a propriedade de {{value}}",
|
||||
"VERIFICATION": "Oferecemos dois métodos para validar manualmente o seu domínio:",
|
||||
"VERIFICATION_HTML": "-HTTP. Hospede um arquivo de verificação temporário em seu site",
|
||||
"VERIFICATION_DNS": "-DNS. Crie uma entrada DNS de registro TXT",
|
||||
"VERIFICATION_DNS_DESC": "Se você gerencia {{ value }} e tem acesso aos seus registros DNS, poderá criar um novo registro TXT com os seguintes valores:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Use este código para o valor do registro TXT:",
|
||||
"VERIFICATION_HTTP_DESC": "Se você tiver acesso à hospedagem do seu site, basta baixar o arquivo de verificação e carregá-lo no URL fornecido",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "URL esperado:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Arquivo de verificação:",
|
||||
"VERIFICATION_SKIP": "Você pode pular a verificação por enquanto e continuar a criar sua organização, mas para usar seu domínio esta etapa precisa ser concluída!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Não exclua o código de verificação, pois a ZITADEL verificará novamente a propriedade do seu domínio de tempos em tempos.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Solicitar novo token",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "O método {{ value }} foi selecionado para verificar seu domínio. Clique no botão para acionar uma verificação ou redefinir o processo de verificação.",
|
||||
"VERIFICATION_SUCCESSFUL": "Domínio verificado com sucesso!",
|
||||
"REQUESTNEWTOKEN": "Solicitar novo token",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "Redefinir método de verificação"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Baixar Arquivo",
|
||||
"SELECTORGTOOLTIP": "Selecionar esta organização.",
|
||||
@ -1020,7 +1024,7 @@
|
||||
"DESCRIPTION": "Essas configurações estendem e sobrescrevem as configurações da sua instância."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Geral",
|
||||
"LANGUAGES": "Idiomas",
|
||||
"LOGIN": "Comportamento de Login e Segurança",
|
||||
"LOCKOUT": "Bloqueio",
|
||||
"COMPLEXITY": "Complexidade de Senha",
|
||||
@ -1049,22 +1053,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Idioma padrão",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Configurações de Idioma",
|
||||
"DEFAULT": "Idioma Padrão",
|
||||
"ALLOWED": "Idiomas Permitidos",
|
||||
"NOT_ALLOWED": "Idiomas Não Permitidos",
|
||||
"ALLOW_ALL": "Permitir Todos os Idiomas",
|
||||
"DISALLOW_ALL": "Não Permitir Todos os Idiomas",
|
||||
"SETASDEFAULT": "Definir como Idioma Padrão",
|
||||
"DEFAULT_SAVED": "Idioma Padrão salvo",
|
||||
"ALLOWED_SAVED": "Idiomas Permitidos salvos",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Configurações SMTP",
|
||||
@ -1263,8 +1277,10 @@
|
||||
"RESET_DESCRIPTION": "Você está prestes a restaurar todos os valores padrão. Todas as alterações que você fez serão excluídas permanentemente. Deseja realmente continuar?",
|
||||
"UNSAVED_TITLE": "Continuar sem salvar?",
|
||||
"UNSAVED_DESCRIPTION": "Você fez alterações sem salvar. Deseja salvar agora?",
|
||||
"LOCALE": "Código de localidade",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Você selecionou um idioma que não é permitido. Você pode continuar modificando os textos. Mas se deseja que seus usuários realmente possam usar este idioma, altere as restrições de suas instâncias.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Não permitido:",
|
||||
"LANGUAGE": "Idioma",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1375,7 +1391,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "O endereço do remetente do SMTP corresponde ao domínio da Instância",
|
||||
"ALLOWUSERNAMEPASSWORD": "Permitir usuário e senha",
|
||||
"ALLOWEXTERNALIDP": "Permitir provedor de ID externo",
|
||||
"ALLOWREGISTER": "Permitir registro",
|
||||
"ALLOWREGISTERUSERS": "Permitir registro de usuários",
|
||||
"ALLOWREGISTERORGS": "Permitir registro de organizações",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "O login convencional com nome de usuário e senha é permitido.",
|
||||
"ALLOWEXTERNALIDP_DESC": "O login é permitido para os provedores de identidade subjacentes",
|
||||
"ALLOWREGISTER_DESC": "Se a opção estiver selecionada, uma etapa adicional para registrar um usuário aparecerá no login.",
|
||||
|
@ -868,14 +868,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "Последовательность",
|
||||
"CHECKBOX": "Фильтровать по последовательности",
|
||||
"SORT": "Сортировка",
|
||||
"ASC": "Восходящий",
|
||||
"DESC": "По убыванию"
|
||||
"CHECKBOX": "Фильтровать по последовательности"
|
||||
},
|
||||
"SORT": "Сортировка",
|
||||
"ASC": "Восходящий",
|
||||
"DESC": "По убыванию",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "Дата создания",
|
||||
"CHECKBOX": "Фильтровать по дате создания"
|
||||
"RADIO_FROM": "От",
|
||||
"RADIO_RANGE": "Диапазон",
|
||||
"LABEL_SINCE": "С",
|
||||
"LABEL_UNTIL": "К"
|
||||
},
|
||||
"OTHER": "другой",
|
||||
"OTHERS": "другие"
|
||||
@ -925,20 +927,22 @@
|
||||
"BTN": "Переименовать"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "Проверка владения доменом организации",
|
||||
"VERIFICATION": "Чтобы подтвердить право собственности на ваш домен, вам необходимо скачать файл подтверждения и загрузить его по предоставленному URL-адресу, указанному ниже, или разместить DNS-запись TXT для предоставленного URL-адреса. Для завершения нажмите кнопку «Подтвердить».",
|
||||
"VERIFICATION_SKIP": "Вы можете пока пропустить проверку и продолжить создание своей организации, но для того, чтобы использовать свою организацию, необходимо выполнить этот шаг!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Токены регулярно проверяются, чтобы убедиться, что вы по-прежнему являетесь владельцем домена.",
|
||||
"TITLE": "Подтвердите право собственности на {{value}}",
|
||||
"VERIFICATION": "Мы предлагаем вам два метода проверки вашего домена вручную:",
|
||||
"VERIFICATION_HTML": "- HTTP. Разместите временный файл подтверждения на своем веб-сайте.",
|
||||
"VERIFICATION_DNS": "- ДНС. Создайте DNS-запись TXT Record.",
|
||||
"VERIFICATION_DNS_DESC": "Если вы управляете {{ value }} и у вас есть доступ к вашим записям DNS, вы можете создать новую запись TXT со следующими значениями:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "Используйте этот код для значения записи TXT:",
|
||||
"VERIFICATION_HTTP_DESC": "Если у вас есть доступ к хостингу вашего веб-сайта, просто скачайте файл подтверждения и загрузите его по указанному URL-адресу.",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "Ожидаемый URL:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "Файл проверки:",
|
||||
"VERIFICATION_SKIP": "Вы можете пока пропустить проверку и продолжить создание своей организации, но для того, чтобы использовать свой домен, необходимо выполнить этот шаг!",
|
||||
"VERIFICATION_VALIDATION_DESC": "Не удаляйте код подтверждения, так как ZITADEL будет время от времени перепроверять право собственности на ваш домен.",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "Запросить новый токен",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "Если вы хотите запросить новый токен, выберите предпочтительный метод. Если вы хотите проверить постоянный токен, нажмите кнопку выше.",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Токен подтверждения уже запрошен. Нажмите кнопку, чтобы запустить проверку.",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "Тип токена:",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "Для подтверждения вашего домена выбран метод {{ value }}. Нажмите кнопку, чтобы запустить проверку или сбросить процесс проверки.",
|
||||
"VERIFICATION_SUCCESSFUL": "Домен успешно подтвержден!",
|
||||
"REQUESTNEWTOKEN": "Запросить новый токен",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "Сбросить метод проверки"
|
||||
},
|
||||
"DOWNLOAD_FILE": "Загрузить файл",
|
||||
"SELECTORGTOOLTIP": "Выберите эту организацию.",
|
||||
@ -1015,7 +1019,7 @@
|
||||
"DESCRIPTION": "Эти настройки расширяют и перезаписывают настройки вашего экземпляра."
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "Общие",
|
||||
"LANGUAGES": "Языки",
|
||||
"LOGIN": "Поведение при входе и безопасность",
|
||||
"LOCKOUT": "Блокировка",
|
||||
"COMPLEXITY": "Сложность пароля",
|
||||
@ -1041,21 +1045,31 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "Язык по умолчанию",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "Настройки языка",
|
||||
"DEFAULT": "Язык по умолчанию",
|
||||
"ALLOWED": "Разрешенные языки",
|
||||
"NOT_ALLOWED": "Неразрешенные языки",
|
||||
"ALLOW_ALL": "Разрешить все языки",
|
||||
"DISALLOW_ALL": "Запретить все языки",
|
||||
"SETASDEFAULT": "Установить как язык по умолчанию",
|
||||
"DEFAULT_SAVED": "Язык по умолчанию сохранен",
|
||||
"ALLOWED_SAVED": "Разрешенные языки сохранены",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "Настройки SMTP",
|
||||
@ -1248,8 +1262,10 @@
|
||||
"RESET_DESCRIPTION": "Вы собираетесь восстановить все значения по умолчанию. Все внесенные вами изменения будут безвозвратно удалены. Вы действительно хотите продолжить?",
|
||||
"UNSAVED_TITLE": "Продолжить без сохранения?",
|
||||
"UNSAVED_DESCRIPTION": "Вы внесли изменения без сохранения. Вы хотите сохранить сейчас?",
|
||||
"LOCALE": "Код региона",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "Вы выбрали язык, который не разрешен. Вы можете продолжить изменять тексты. Но если вы хотите, чтобы ваши пользователи могли фактически использовать этот язык, измените ограничения ваших экземпляров.",
|
||||
"LANGUAGES_NOT_ALLOWED": "Не разрешено:",
|
||||
"LANGUAGE": "Язык",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1261,6 +1277,7 @@
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
},
|
||||
@ -1359,7 +1376,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "Адрес отправителя SMTP соответствует домену экземпляра",
|
||||
"ALLOWUSERNAMEPASSWORD": "Вход с паролем разрешен",
|
||||
"ALLOWEXTERNALIDP": "Внешний поставщик разрешен",
|
||||
"ALLOWREGISTER": "Регистрация разрешена",
|
||||
"ALLOWREGISTERUSERS": "Регистрация пользователей разрешена",
|
||||
"ALLOWREGISTERORGS": "Регистрация организаций разрешена",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "Разрешен обычный вход в систему с использованием имени пользователя и паролем.",
|
||||
"ALLOWEXTERNALIDP_DESC": "Вход разрешен для базовых поставщиков удостоверений.",
|
||||
"ALLOWREGISTER_DESC": "Если опция выбрана, в логине появляется дополнительный шаг для регистрации пользователя.",
|
||||
|
@ -871,14 +871,16 @@
|
||||
},
|
||||
"SEQUENCE": {
|
||||
"LABEL": "序列",
|
||||
"CHECKBOX": "按顺序过滤",
|
||||
"SORT": "分拣",
|
||||
"ASC": "上升中",
|
||||
"DESC": "下降"
|
||||
"CHECKBOX": "按顺序过滤"
|
||||
},
|
||||
"SORT": "分拣",
|
||||
"ASC": "上升中",
|
||||
"DESC": "下降",
|
||||
"CREATIONDATE": {
|
||||
"LABEL": "创建日期",
|
||||
"CHECKBOX": "按创建日期过滤"
|
||||
"RADIO_FROM": "从",
|
||||
"RADIO_RANGE": "范围",
|
||||
"LABEL_SINCE": "自从",
|
||||
"LABEL_UNTIL": "直到"
|
||||
},
|
||||
"OTHER": "其他",
|
||||
"OTHERS": "其他"
|
||||
@ -928,20 +930,22 @@
|
||||
"BTN": "改名"
|
||||
},
|
||||
"ORGDOMAIN": {
|
||||
"TITLE": "组织域所有权验证",
|
||||
"VERIFICATION": "要验证您对域的所有权,您需要下载验证文件并将其上传到下面列出的提供的 URL,或者为提供的域名添加一条类型为TXT的DNS解析记录。完成后请单击按钮进行验证。",
|
||||
"VERIFICATION_SKIP": "您现在可以跳过验证并继续创建您的组织,但要使用您的组织,必须完成此步骤!",
|
||||
"VERIFICATION_VALIDATION_DESC": "定期检查令牌以确保您仍然是域的所有者。",
|
||||
"TITLE": "验证 {{value}} 所有权",
|
||||
"VERIFICATION": "我们为您提供两种手动验证域的方法:",
|
||||
"VERIFICATION_HTML": "- HTTP。在您的网站上托管临时验证文件",
|
||||
"VERIFICATION_DNS": "- DNS。创建 TXT 记录 DNS 条目",
|
||||
"VERIFICATION_DNS_DESC": "如果您管理 {{ value }} 并且有权访问您的 DNS 记录,则可以使用以下值创建新的 TXT 记录:",
|
||||
"VERIFICATION_DNS_HOST_LABEL": "Host:",
|
||||
"VERIFICATION_DNS_CHALLENGE_LABEL": "使用此代码作为 TXT 记录的值:",
|
||||
"VERIFICATION_HTTP_DESC": "如果您有权访问您的网站托管,只需下载验证文件并将其上传到提供的 URL",
|
||||
"VERIFICATION_HTTP_URL_LABEL": "预期网址:",
|
||||
"VERIFICATION_HTTP_FILE_LABEL": "验证文件:",
|
||||
"VERIFICATION_SKIP": "您现在可以跳过验证并继续创建您的组织,但为了使用您的域,必须完成此步骤!",
|
||||
"VERIFICATION_VALIDATION_DESC": "不要删除验证码,因为 ZITADEL 会不时重新检查您的域名所有权。",
|
||||
"VERIFICATION_NEWTOKEN_TITLE": "请求新令牌",
|
||||
"VERIFICATION_NEWTOKEN_DESC": "如果您想请求新令牌,请选择您喜欢的方法。如果要验证持久性令牌,请单击上面的按钮。",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "已请求验证令牌,单击按钮以触发验证检查。",
|
||||
"VERIFICATION_VALIDATION_ONGOING_TYPE": "输入令牌:",
|
||||
"VERIFICATION_VALIDATION_ONGOING": "已选择 {{ value }} 方法来验证您的域。单击该按钮可触发验证检查或重置验证过程。",
|
||||
"VERIFICATION_SUCCESSFUL": "域名验证成功!",
|
||||
"REQUESTNEWTOKEN": "请求新令牌",
|
||||
"TYPES": {
|
||||
"1": "HTTP",
|
||||
"2": "DNS"
|
||||
}
|
||||
"RESETMETHOD": "重置验证方式"
|
||||
},
|
||||
"DOWNLOAD_FILE": "下载文件",
|
||||
"SELECTORGTOOLTIP": "选择此组织。",
|
||||
@ -1018,7 +1022,7 @@
|
||||
"DESCRIPTION": "这些设置将扩展或覆盖您的实例设置。"
|
||||
},
|
||||
"LIST": {
|
||||
"GENERAL": "通用",
|
||||
"LANGUAGES": "语言",
|
||||
"LOGIN": "登录行为和安全",
|
||||
"LOCKOUT": "安全锁策略",
|
||||
"COMPLEXITY": "密码复杂性",
|
||||
@ -1047,22 +1051,32 @@
|
||||
}
|
||||
},
|
||||
"SETTING": {
|
||||
"DEFAULTLANGUAGE": "默认语言",
|
||||
"LANGUAGE": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
"LANGUAGES": {
|
||||
"TITLE": "语言设置",
|
||||
"DEFAULT": "默认语言",
|
||||
"ALLOWED": "允许的语言",
|
||||
"NOT_ALLOWED": "不允许的语言",
|
||||
"ALLOW_ALL": "允许所有语言",
|
||||
"DISALLOW_ALL": "禁止所有语言",
|
||||
"SETASDEFAULT": "设置为默认语言",
|
||||
"DEFAULT_SAVED": "默认语言已保存",
|
||||
"ALLOWED_SAVED": "允许的语言已保存",
|
||||
"OPTIONS": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
"fr": "Français",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"pl": "Polski",
|
||||
"zh": "简体中文",
|
||||
"bg": "Български",
|
||||
"pt": "Portuguese",
|
||||
"mk": "Македонски",
|
||||
"cs": "Čeština",
|
||||
"ru": "Русский",
|
||||
"nl": "Nederlands"
|
||||
}
|
||||
},
|
||||
"SMTP": {
|
||||
"TITLE": "SMTP 设置",
|
||||
@ -1260,8 +1274,10 @@
|
||||
"RESET_DESCRIPTION": "您即将恢复所有默认值。您所做的所有更改都将被永久删除。你真的要继续吗?",
|
||||
"UNSAVED_TITLE": "继续但不保存?",
|
||||
"UNSAVED_DESCRIPTION": "您在未保存的情况下进行了更改。您现在要保存吗?",
|
||||
"LOCALE": "本地化",
|
||||
"LOCALES": {
|
||||
"ACTIVE_LANGUAGE_NOT_ALLOWED": "您选择了不允许的语言。您可以继续修改文本。但是,如果您希望您的用户实际上能够使用此语言,请更改您的实例限制。",
|
||||
"LANGUAGES_NOT_ALLOWED": "不允许:",
|
||||
"LANGUAGE": "语言",
|
||||
"LANGUAGES": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"es": "Español",
|
||||
@ -1372,7 +1388,8 @@
|
||||
"SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN": "SMTP 发件人地址与实例域名匹配",
|
||||
"ALLOWUSERNAMEPASSWORD": "允许用户名密码",
|
||||
"ALLOWEXTERNALIDP": "允许外部身份提供者",
|
||||
"ALLOWREGISTER": "允许注册",
|
||||
"ALLOWREGISTERUSERS": "允许注册用户",
|
||||
"ALLOWREGISTERORGS": "允许注册组织",
|
||||
"ALLOWUSERNAMEPASSWORD_DESC": "允许使用用户名和密码进行登录。",
|
||||
"ALLOWEXTERNALIDP_DESC": "允许外部身份提供者进行登录",
|
||||
"ALLOWREGISTER_DESC": "如果选择了该选项,登录中会出现一个用于注册用户的附加步骤。",
|
||||
|
@ -65,6 +65,7 @@
|
||||
@import 'src/app/modules/policies/login-policy/factor-table/factor-table.component.scss';
|
||||
@import 'src/app/modules/info-overlay/info-overlay.component.scss';
|
||||
@import 'src/app/modules/create-layout/create-layout.component.scss';
|
||||
@import 'src/app/modules/domains/domain-verification/domain-verification.component.scss';
|
||||
@import './styles/codemirror.scss';
|
||||
|
||||
@mixin component-themes($theme) {
|
||||
@ -136,4 +137,5 @@
|
||||
@include codemirror-theme($theme);
|
||||
@include contact-theme($theme);
|
||||
@include app-create-theme($theme);
|
||||
@include domain-verification-theme($theme);
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ It demonstrates how to fetch some data from the ZITADEL management API.
|
||||
|
||||
At the end of the guide you should have an application able to read the details of your organization.
|
||||
|
||||
> This documentation references our [CLI example](https://github.com/zitadel/zitadel-go/blob/next/example/client/cli/cli.go).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The client [SDK](https://github.com/zitadel/zitadel-go) will handle all necessary OAuth 2.0 requests and send the required headers to the ZITADEL API using our [OIDC client library](https://github.com/zitadel/oidc).
|
||||
@ -26,109 +28,36 @@ However, we recommend you read the guide on [how to access ZITADEL API](../../gu
|
||||
You need to add the SDK into Go Modules by:
|
||||
|
||||
```bash
|
||||
go get github.com/zitadel/zitadel-go/v2
|
||||
go get -u github.com/zitadel/zitadel-go/v3
|
||||
```
|
||||
|
||||
### Create example client
|
||||
|
||||
Create a new go file with the content below. This will create a client for the management api and call its `GetMyOrg` function.
|
||||
Create a new go file with the content below. This will create a client and call its `GetMyOrg` function on the ManagementService.
|
||||
The SDK will make sure you will have access to the API by retrieving a Bearer Token using JWT Profile with the provided scopes (`openid` and `urn:zitadel:iam:org:project:id:zitadel:aud`).
|
||||
Make sure to fill the vars `issuer` and `api`.
|
||||
|
||||
The issuer and api is the domain of your instance you can find it on the instance detail in the ZITADEL Cloud Customer Portal or in the ZITADEL Console.
|
||||
|
||||
:::note
|
||||
The issuer will require the protocol (`https://` and `http://`) and you will only have to specify a port if they're not default (443 for https and 80 for http). The API will always require a port, but no protocol.
|
||||
:::
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log"
|
||||
|
||||
"github.com/zitadel/oidc/pkg/oidc"
|
||||
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/management"
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/zitadel"
|
||||
pb "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/management"
|
||||
)
|
||||
|
||||
var (
|
||||
issuer = flag.String("issuer", "", "issuer of your ZITADEL instance (in the form: https://<instance>.zitadel.cloud or https://<yourdomain>)")
|
||||
api = flag.String("api", "", "gRPC endpoint of your ZITADEL instance (in the form: <instance>.zitadel.cloud:443 or <yourdomain>:443)")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
//create a client for the management api providing:
|
||||
//- issuer (e.g. https://acme-dtfhdg.zitadel.cloud)
|
||||
//- api (e.g. acme-dtfhdg.zitadel.cloud:443)
|
||||
//- scopes (including the ZITADEL project ID),
|
||||
//- a JWT Profile token source (e.g. path to your key json), if not provided, the file will be read from the path set in env var ZITADEL_KEY_PATH
|
||||
client, err := management.NewClient(
|
||||
*issuer,
|
||||
*api,
|
||||
[]string{oidc.ScopeOpenID, zitadel.ScopeZitadelAPI()},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalln("could not create client", err)
|
||||
}
|
||||
defer func() {
|
||||
err := client.Connection.Close()
|
||||
if err != nil {
|
||||
log.Println("could not close grpc connection", err)
|
||||
}
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
//call ZITADEL and print the name and creation date of your organisation
|
||||
//the call was successful if no error occurred
|
||||
resp, err := client.GetMyOrg(ctx, &pb.GetMyOrgRequest{})
|
||||
if err != nil {
|
||||
log.Fatalln("call failed: ", err)
|
||||
}
|
||||
log.Printf("%s was created on: %s", resp.Org.Name, resp.Org.Details.CreationDate.AsTime())
|
||||
}
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/client/cli/cli.go
|
||||
```
|
||||
|
||||
#### Key JSON
|
||||
|
||||
To provide the key JSON to the SDK, simply set an environment variable `ZITADEL_KEY_PATH` with the path to the JSON as value.
|
||||
|
||||
```bash
|
||||
export ZITADEL_KEY_PATH=/Users/test/servicekey.json
|
||||
```
|
||||
|
||||
For development purposes you should be able to set this in your IDE.
|
||||
|
||||
If you're not able to set it via environment variable, you can also pass it with an additional option:
|
||||
|
||||
```go
|
||||
client, err := management.NewClient(
|
||||
[]string{oidc.ScopeOpenID, zitadel.ScopeZitadelAPI()},
|
||||
zitadel.WithKeyPath("/Users/test/servicekey.json"),
|
||||
)
|
||||
```
|
||||
|
||||
### Test client
|
||||
### Test
|
||||
|
||||
After you have configured everything correctly, you can simply start the example by:
|
||||
|
||||
```bash
|
||||
go run main.go
|
||||
go run cli.go --domain <your domain> --key <path>
|
||||
```
|
||||
|
||||
This could look like:
|
||||
|
||||
```bash
|
||||
go run cli.go --domain my-domain.zitadel.cloud --key ./api.json
|
||||
```
|
||||
|
||||
This will output something similar to:
|
||||
|
||||
```
|
||||
2021/04/21 11:27:36 DemoOrg was created on: 2021-04-08 13:36:05.578194 +0000 UTC
|
||||
2023/12/20 08:48:23 INFO retrieved the organisation orgID=165467338479501569 name=DemoOrg
|
||||
```
|
||||
|
||||
## Completion
|
||||
@ -143,16 +72,12 @@ If you've run into any other problem, don't hesitate to contact us or raise an i
|
||||
|
||||
### Whats next?
|
||||
|
||||
Now you can proceed implementing our APIs by adding more calls or trying to overwrite the organization context:
|
||||
Now you can proceed implementing our APIs by adding more calls or using a different service like the SessionService:
|
||||
|
||||
```go
|
||||
respOverwrite, err := client.GetMyOrg(middleware.SetOrgID(ctx, "74161146763996133"), &pb.GetMyOrgRequest{})
|
||||
if err != nil {
|
||||
log.Fatalln("call failed: ", err)
|
||||
}
|
||||
log.Printf("%s was created on: %s", respOverwrite.Org.Name, respOverwrite.Org.Details.CreationDate.AsTime())
|
||||
}
|
||||
api.SessionService().CreateSession(ctx, &session.CreateSessionRequest{})
|
||||
```
|
||||
Checkout more [examples from the SDK](https://github.com/zitadel/zitadel-go/blob/main/example) or refer to our [API Docs](/apis/introduction).
|
||||
Checkout more [examples from the SDK](https://github.com/zitadel/zitadel-go/blob/next/example),
|
||||
like how you can integrate the [client in your own API](https://github.com/zitadel/zitadel-go/blob/next/example/api/client/main.go)
|
||||
or refer to our [API Docs](/apis/introduction).
|
||||
|
||||
> This guide will be updated soon to show you how to use the SDK for your own API as well.
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Overview of ZITADEL Examples, Quickstarts, and SDKs
|
||||
title: Overview of ZITADEL example applications and quickstarts
|
||||
sidebar_label: Overview
|
||||
---
|
||||
|
||||
@ -91,9 +91,9 @@ Our examples cover a range of programming languages and frameworks, so no matter
|
||||
<img src="/docs/img/tech/golang.svg" alt="golang"/>
|
||||
</td>
|
||||
<td>Go Web</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><a href="./sdks">SDK</a></td>
|
||||
<td><a href="https://github.com/zitadel/zitadel-go/tree/next/example/app" target="_blank"><i class="lab la-github"></i></a></td>
|
||||
<td><a href="/examples/login/go">Guide</a></td>
|
||||
<td><a href="https://github.com/zitadel/zitadel-go/tree/next" target="_blank">SDK</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100px">
|
||||
@ -148,9 +148,9 @@ Our examples cover a range of programming languages and frameworks, so no matter
|
||||
<img src="/docs/img/tech/golang.svg" alt="golang"/>
|
||||
</td>
|
||||
<td>Golang</td>
|
||||
<td><a href="https://github.com/zitadel/zitadel-go" target="_blank"><i class="lab la-github"></i></a></td>
|
||||
<td><a href="https://github.com/zitadel/zitadel-go/tree/next/example/api" target="_blank"><i class="lab la-github"></i></a></td>
|
||||
<td><a href="./secure-api/go">Guide</a></td>
|
||||
<td><a href="https://github.com/zitadel/zitadel-go" target="_blank">SDK</a></td>
|
||||
<td><a href="https://github.com/zitadel/zitadel-go/tree/next" target="_blank">SDK</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
@ -198,3 +198,12 @@ Our examples cover a range of programming languages and frameworks, so no matter
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Other example applications
|
||||
|
||||
- [B2B customer portal](https://github.com/zitadel/zitadel-nextjs-b2b): Showcase the use of personal access tokens in a B2B environment. Uses NextJS Framework.
|
||||
- [Frontend with backend API](https://github.com/zitadel/example-quote-generator-app): A simple web application using a React front-end and a Python back-end API, both secured using ZITADEL
|
||||
- [Introspection](https://github.com/zitadel/examples-api-access-and-token-introspection): Python examples for securing an API and invoking it as a service user
|
||||
- [Fine-grained authorization](https://github.com/zitadel/example-fine-grained-authorization): Leverage actions, custom metadata, and claims for attribute-based access control
|
||||
|
||||
Search for the "example" tag in our repository to [explore all examples](https://github.com/search?q=topic%3Aexamples+org%3Azitadel&type=repositories).
|
||||
|
152
docs/docs/examples/login/go.md
Normal file
152
docs/docs/examples/login/go.md
Normal file
@ -0,0 +1,152 @@
|
||||
---
|
||||
title: ZITADEL with Go
|
||||
sidebar_label: Go
|
||||
---
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Go web application.
|
||||
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
|
||||
|
||||
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
|
||||
|
||||
> This documentation references our [example](https://github.com/zitadel/zitadel-go) on GitHub.
|
||||
> You can either create your own application or directly run the example by providing the necessary arguments.
|
||||
|
||||
## Set up application
|
||||
|
||||
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Console.
|
||||
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
|
||||
Select the **Web** application type and continue.
|
||||
|
||||

|
||||
|
||||
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all applications.
|
||||
|
||||

|
||||
|
||||
### Redirect URIs
|
||||
|
||||
The Redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
The Post-logout redirect send the users back to a route on your application after they have logged out.
|
||||
|
||||
> If you are following along with the [example](https://github.com/zitadel/zitadel-go), set the dev mode to `true`, the Redirect URIs to <http://localhost:8089/auth/callback> and Post redirect URI to <http://localhost:8089/>.
|
||||
|
||||

|
||||
|
||||
Continue and create the application.
|
||||
|
||||
### Client ID
|
||||
|
||||
After successful creation of the app, a pop-up will appear displaying the app's client ID. Copy the client ID, as you will need it to configure your Go client.
|
||||
|
||||

|
||||
|
||||
## Go setup
|
||||
|
||||
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Go client.
|
||||
|
||||
### Install ZITADEL Go SDK
|
||||
|
||||
To connect with ZITADEL, you need to install an OAuth/OIDC client. Run the following command:
|
||||
|
||||
```bash
|
||||
go get -u github.com/zitadel/zitadel-go/v3
|
||||
```
|
||||
|
||||
### Create the application server
|
||||
|
||||
Create a new go file with the content below. This will create an application with a home and profile page.
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/app/app.go
|
||||
```
|
||||
|
||||
This will basically set up everything. So let's look at some parts of the code.
|
||||
|
||||
**Register authentication handler**:
|
||||
|
||||
For the authentication to work, the SDK needs some handlers in your application.
|
||||
In this example we will register them on the `/auth/` prefix.
|
||||
The SDK itself will then register three routes on that to be able to:
|
||||
- start the authentication process and redirect to the Login UI (`/auth/login`)
|
||||
- continue with the authentication process after the login UI (`/auth/callback`)
|
||||
- terminate the session (`/auth/logout`)
|
||||
-
|
||||
```go
|
||||
router.Handle("/auth/", z.Authentication)
|
||||
```
|
||||
|
||||
***Authentication checks***
|
||||
|
||||
To ensure the user is authenticated before they are able to use your application, the middleware provides two options:
|
||||
- You can either require the user to be authenticated. If he's not yet, he will be automatically redirected to the Login UI:
|
||||
```go
|
||||
mw.RequireAuthentication()(handler)
|
||||
```
|
||||
- You can just check if he already is, but still continue serving the page:
|
||||
```go
|
||||
mw.CheckAuthentication()(handler)
|
||||
```
|
||||
|
||||
***Authentication context***
|
||||
|
||||
If you used either of the authentication checks above, you can then access context information in your handler:
|
||||
```go
|
||||
mw.Context(req.Context())
|
||||
```
|
||||
|
||||
### Add pages to your application
|
||||
|
||||
To be able to serve these pages create a `templates` directory in the same folder as you just created the go file.
|
||||
Now create two HTML files in the new `templates` folder and copy the content of the examples:
|
||||
|
||||
**home.html**
|
||||
|
||||
The home page will display a short welcome message and allow the user to manually start the login process.
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/app/templates/home.html
|
||||
```
|
||||
|
||||
**profile.html**
|
||||
|
||||
The profile page will display the Userinfo from the authentication context and allow the user to logout.
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/app/templates/profile.html
|
||||
```
|
||||
|
||||
### Start your application
|
||||
|
||||
You will need to provide some values for the program to run:
|
||||
- `domain`: Your ZITADEL instance domain, e.g. my-domain.zitadel.cloud
|
||||
- `key`: The path to the downloaded key.json
|
||||
- `clientID`: The clientID provided by ZITADEL
|
||||
- `redirectURI`: The redirectURI registered at ZITADEL
|
||||
- `port`: The port on which the API will be accessible, default it 8089
|
||||
|
||||
```bash
|
||||
go run main.go --domain <your domain> --key <key> -- clientID <clientID> --redirectURI <redirectURI>
|
||||
```
|
||||
|
||||
This could look like:
|
||||
|
||||
```bash
|
||||
go run main.go --domain my-domain.zitadel.cloud --key XKv2Lqd7YAq13NUZVUWZEWZeruqyzViM --clientID 243861220627644836@example --redirectURI http://localhost:8089/auth/callback
|
||||
```
|
||||
|
||||
If you then visit on http://localhost:8089 you should get the following screen:
|
||||
|
||||

|
||||
|
||||
By clicking on `Login` you will be redirected to your ZITADEL instance. After login with your existing user you will be presented the profile page:
|
||||
|
||||

|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Go application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-go) application.
|
||||
This application includes all the functionalities mentioned in this quickstart.
|
||||
You can directly start it with your own configuration. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel-go/issues).
|
||||
|
@ -4,20 +4,21 @@ sidebar_label: SDKs
|
||||
---
|
||||
|
||||
On this page you find our official SDKs, links to supporting frameworks and providers, and resources to help with SDKs.
|
||||
The SDKs wrap either our [gRPC or REST APIs](/docs/apis/introduction) to provide the client with User Authentication and Management for resources.
|
||||
The SDKs wrap either our [gRPC or REST APIs](/docs/apis/introduction) to provide the client with User Authentication and
|
||||
Management for resources.
|
||||
|
||||
## ZITADEL SDKs
|
||||
|
||||
| Language / Framework | Link Github | User Authentication | Manage resources | Notes |
|
||||
|----------------------|---------------------------------------------------------------| --- | --- | --- |
|
||||
| .NET | [zitadel-net](https://github.com/smartive/zitadel-net) | ✔️ | ✔️ | `community` |
|
||||
| Elixir | [zitadel_api](https://github.com/jshmrtn/zitadel_api) | ✔️ | ✔️ | `community` |
|
||||
| Go | [zitadel-go](https://github.com/zitadel/zitadel-go) | ❌ | ✔️ | `official` |
|
||||
| JVM | 🚧 [WIP](https://github.com/zitadel/zitadel/discussions/3650) | ❓ | ❓ | TBD |
|
||||
| Python | 🚧 [WIP](https://github.com/zitadel/zitadel/issues/3675) | ❓ | ❓ | TBD |
|
||||
| NodeJS | [@zitadel/node](https://www.npmjs.com/package/@zitadel/node) | ❌ | ✔️ | `community` |
|
||||
| Dart | [zitadel-dart](https://github.com/smartive/zitadel-dart) | ❌ | ✔️ | `community` |
|
||||
| Rust | [zitadel-rust](https://github.com/smartive/zitadel-rust) | ✔️ | ✔️ | `community` |
|
||||
| Language / Framework | Link Github | User Authentication | Manage resources | Notes |
|
||||
|----------------------|---------------------------------------------------------------|-----------------------------------------------------------|------------------|-------------|
|
||||
| .NET | [zitadel-net](https://github.com/smartive/zitadel-net) | ✔️ | ✔️ | `community` |
|
||||
| Elixir | [zitadel_api](https://github.com/jshmrtn/zitadel_api) | ✔️ | ✔️ | `community` |
|
||||
| Go | [zitadel-go](https://github.com/zitadel/zitadel-go) | 🚧 [WIP](https://github.com/zitadel/zitadel-go/tree/next) | ✔️ | `official` |
|
||||
| JVM | 🚧 [WIP](https://github.com/zitadel/zitadel/discussions/3650) | ❓ | ❓ | TBD |
|
||||
| Python | 🚧 [WIP](https://github.com/zitadel/zitadel/issues/3675) | ❓ | ❓ | TBD |
|
||||
| NodeJS | [@zitadel/node](https://www.npmjs.com/package/@zitadel/node) | ❌ | ✔️ | `community` |
|
||||
| Dart | [zitadel-dart](https://github.com/smartive/zitadel-dart) | ❌ | ✔️ | `community` |
|
||||
| Rust | [zitadel-rust](https://github.com/smartive/zitadel-rust) | ✔️ | ✔️ | `community` |
|
||||
|
||||
## Missing SDK
|
||||
|
||||
@ -27,7 +28,8 @@ Is your language/framework missing? Fear not, you can generate your gRPC API Cli
|
||||
2. Create a `buf.gen.yaml` and configure the [plugins](https://buf.build/plugins) you need
|
||||
3. Run `buf generate https://github.com/zitadel/zitadel#format=git,tag=v2.23.1` (change the versions to your needs)
|
||||
|
||||
Let us make an example with Ruby. Any other supported language by buf will work as well. Consult the [buf plugin registry](https://buf.build/plugins) for more ideas.
|
||||
Let us make an example with Ruby. Any other supported language by buf will work as well. Consult
|
||||
the [buf plugin registry](https://buf.build/plugins) for more ideas.
|
||||
|
||||
### Example with Ruby
|
||||
|
||||
@ -43,7 +45,8 @@ plugins:
|
||||
out: gen
|
||||
```
|
||||
|
||||
If you now run `buf generate https://github.com/zitadel/zitadel#format=git,tag=v2.23.1` in the folder where your `buf.gen.yaml` is located you should see the folder `gen` appear.
|
||||
If you now run `buf generate https://github.com/zitadel/zitadel#format=git,tag=v2.23.1` in the folder where
|
||||
your `buf.gen.yaml` is located you should see the folder `gen` appear.
|
||||
|
||||
If you run `ls -la gen/zitadel/` you should see something like this:
|
||||
|
||||
@ -86,12 +89,14 @@ Import these files into your project to start interacting with ZITADEL's APIs.
|
||||
|
||||
## More
|
||||
|
||||
While we are not actively maintaining the following projects, it is worth checking out if you're interested in exploring ZITADEL in different programming languages or frameworks.
|
||||
While we are not actively maintaining the following projects, it is worth checking out if you're interested in exploring
|
||||
ZITADEL in different programming languages or frameworks.
|
||||
|
||||
- [NodeJS passport](https://github.com/buehler/node-passport-zitadel) authentication helper
|
||||
- [NextAuth Provider for ZITADEL](https://next-auth.js.org/providers/zitadel)
|
||||
|
||||
If we do not provide an example, SDK or guide, we strongly recommend using existing authentication libraries for your language or framework instead of building your own.
|
||||
If we do not provide an example, SDK or guide, we strongly recommend using existing authentication libraries for your
|
||||
language or framework instead of building your own.
|
||||
Certified libraries have undergone rigorous testing and validation to ensure high security and reliability.
|
||||
There are many recommended libraries available, this saves time and ensures that users' data is well-protected.
|
||||
|
||||
|
@ -8,9 +8,26 @@ OAuth 2 Token Introspection.
|
||||
|
||||
At the end of the guide you should have an API with a protected endpoint.
|
||||
|
||||
> This documentation references our HTTP example. There's also one for GRPC. Check them out on [GitHub](https://github.com/zitadel/zitadel-go/tree/authorization/example/api).
|
||||
|
||||
## Set up application and obtain keys
|
||||
|
||||
Before we begin developing our API, we need to perform a few configuration steps in the ZITADEL Console.
|
||||
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
|
||||
Select the **API** application type and continue.
|
||||
|
||||

|
||||
|
||||
We recommend that you use JWT Profile for authenticating at the Introspection Endpoint.
|
||||
|
||||

|
||||
|
||||
Then create a new key with your desired expiration date. Be sure to download it, as you won't be able to retrieve it again.
|
||||
|
||||

|
||||
|
||||
## Prerequisites
|
||||
|
||||
The client [SDK](https://github.com/zitadel/zitadel-go) will provides an interceptor for both GRPC and HTTP.
|
||||
This will handle the OAuth 2.0 introspection request including authentication using JWT with Private Key using our [OIDC client library](https://github.com/zitadel/oidc).
|
||||
All that is required, is to create your API and download the private key file later called `Key JSON` for the service user.
|
||||
|
||||
@ -18,134 +35,170 @@ All that is required, is to create your API and download the private key file la
|
||||
|
||||
### Add Go SDK to your project
|
||||
|
||||
You need to add the SDK into Go Modules by:
|
||||
You need to add the [SDK](https://github.com/zitadel/zitadel-go) into Go Modules by:
|
||||
|
||||
```bash
|
||||
go get github.com/zitadel/zitadel-go/v2
|
||||
go get -u github.com/zitadel/zitadel-go/v3
|
||||
```
|
||||
|
||||
### Create example API
|
||||
|
||||
Create a new go file with the content below. This will create an API with two endpoints. On path `/public` it will always write
|
||||
back `ok` and the current timestamp. On `/protected` it will respond the same but only if a valid access_token is sent. The token
|
||||
must not be expired and the API has to be part of the audience (either client_id or project_id).
|
||||
Create a new go file with the content below. This will create an API with three endpoints:
|
||||
- `/api/healthz`: can be called by anyone and always returns `OK`
|
||||
- `/api/tasks`: requires authorization and returns the available tasks
|
||||
- `/api/add-task`: requires authorization with granted `admin` role and adds the task to the list
|
||||
|
||||
Make sure to fill the var `issuer` with your own domain. This is the domain of your instance you can find it on the instance detail in the ZITADEL Cloud Customer Portal or in the ZITADEL Console.
|
||||
```go
|
||||
package main
|
||||
If authorization is required, the token must not be expired and the API has to be part of the audience (either client_id or project_id).
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
http_mw "github.com/zitadel/zitadel-go/v2/pkg/api/middleware/http"
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||
)
|
||||
|
||||
var (
|
||||
issuer = flag.String("issuer", "", "issuer of your ZITADEL instance (in the form: https://<instance>.zitadel.cloud or https://<yourdomain>)")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
introspection, err := http_mw.NewIntrospectionInterceptor(*issuer, middleware.OSKeyPath())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
router := http.NewServeMux()
|
||||
router.HandleFunc("/public", writeOK)
|
||||
router.HandleFunc("/protected", introspection.HandlerFunc(writeOK))
|
||||
|
||||
lis := "127.0.0.1:5001"
|
||||
log.Fatal(http.ListenAndServe(lis, router))
|
||||
}
|
||||
|
||||
func writeOK(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("OK " + time.Now().String()))
|
||||
}
|
||||
For tests we will use a Personal Access Token.
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/api/http/main.go
|
||||
```
|
||||
|
||||
#### Key JSON
|
||||
You will need to provide some values for the program to run:
|
||||
- `domain`: Your ZITADEL instance domain, e.g. https://my-domain.zitadel.cloud
|
||||
- `key`: The path to the downloaded key.json
|
||||
- `port`: The port on which the API will be accessible, default it 8089
|
||||
|
||||
To provide the key JSON to the SDK, simply set an environment variable `ZITADEL_KEY_PATH` with the path to the JSON as value.
|
||||
|
||||
```bash
|
||||
export ZITADEL_KEY_PATH=/Users/test/apikey.json
|
||||
```
|
||||
|
||||
For development purposes you should be able to set this in your IDE.
|
||||
|
||||
If you're not able to set it via environment variable, you can also exchange the `middleware.OSKeyPath()` and pass it directly:
|
||||
|
||||
```go
|
||||
introspection, err := http_mw.NewIntrospectionInterceptor(
|
||||
client.Issuer,
|
||||
"/Users/test/apikey.json",
|
||||
)
|
||||
```
|
||||
|
||||
### Test API
|
||||
## Test API
|
||||
|
||||
After you have configured everything correctly, you can simply start the example by:
|
||||
|
||||
```bash
|
||||
go run main.go
|
||||
go run main.go --domain <your domain> --key <path>
|
||||
```
|
||||
|
||||
You can now call the API by browser or curl. Try the public endpoint first:
|
||||
This could look like:
|
||||
|
||||
```bash
|
||||
curl -i localhost:5001/public
|
||||
go run main.go --domain my-domain.zitadel.cloud --key ./api.json
|
||||
```
|
||||
|
||||
After you get a successful log:
|
||||
```
|
||||
2023/12/04 10:27:42 INFO server listening, press ctrl+c to stop addr=http://localhost:8089
|
||||
```
|
||||
|
||||
### Public endpoint
|
||||
|
||||
Now you can call the API by browser or curl. Try the healthz endpoint first:
|
||||
|
||||
```bash
|
||||
curl -i http://localhost:8089/api/healthz
|
||||
```
|
||||
|
||||
it should return something like:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 24 Aug 2021 11:11:17 GMT
|
||||
Content-Length: 59
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Content-Type: application/json
|
||||
Date: Mon, 04 Dec 2023 09:29:38 GMT
|
||||
Content-Length: 4
|
||||
|
||||
OK 2021-08-24 13:11:17.135719 +0200 CEST m=+30704.913892168
|
||||
"OK"
|
||||
```
|
||||
|
||||
and the protected:
|
||||
### Task list
|
||||
|
||||
and the task list endpoint:
|
||||
|
||||
```bash
|
||||
curl -i localhost:5001/protected
|
||||
curl -i http://localhost:8089/api/tasks
|
||||
```
|
||||
|
||||
it will return:
|
||||
|
||||
```
|
||||
HTTP/1.1 401 Unauthorized
|
||||
Content-Type: application/json
|
||||
Date: Tue, 24 Aug 2021 11:13:10 GMT
|
||||
Content-Length: 21
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
X-Content-Type-Options: nosniff
|
||||
Date: Mon, 04 Dec 2023 09:41:54 GMT
|
||||
Content-Length: 44
|
||||
|
||||
"auth header missing"
|
||||
unauthorized: authorization header is empty
|
||||
```
|
||||
|
||||
Get a valid access_token for the API. You can achieve this by login into an application of the same project or
|
||||
by explicitly requesting the project_id for the audience by scope `urn:zitadel:iam:org:project:id:{projectid}:aud`.
|
||||
Get a valid access_token for the API. You can either achieve this by getting an access token with the project_id in the audience
|
||||
or use a PAT of a service account.
|
||||
|
||||
If you provide a valid Bearer Token:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" localhost:5001/protected
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:8089/api/tasks
|
||||
```
|
||||
|
||||
it will return an OK response as well:
|
||||
it will return an empty list:
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 24 Aug 2021 11:13:33 GMT
|
||||
Content-Length: 59
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Content-Type: application/json
|
||||
Date: Mon, 04 Dec 2023 09:49:06 GMT
|
||||
Content-Length: 2
|
||||
|
||||
OK 2021-08-24 13:13:33.131943 +0200 CEST m=+30840.911149251
|
||||
{}
|
||||
```
|
||||
|
||||
### Try to add a new task
|
||||
|
||||
Let's see what happens if you call the AddTask endpoint:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:8089/api/add-task
|
||||
```
|
||||
|
||||
it will complain about the missing `admin` role:
|
||||
```
|
||||
HTTP/1.1 403 Forbidden
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
X-Content-Type-Options: nosniff
|
||||
Date: Mon, 04 Dec 2023 09:52:00 GMT
|
||||
Content-Length: 50
|
||||
|
||||
permission denied: missing required role: `admin`
|
||||
```
|
||||
|
||||
### Add admin role
|
||||
|
||||
So let's create the role and grant it to the user. To do so, go to your project in ZITADEL Console
|
||||
and create the role by selecting `Roles` in the navigation and then clicking on the `New Role` button.
|
||||
Finally, create the role as shown below:
|
||||
|
||||

|
||||
|
||||
After you have created the role, let's grant it the user, who requested the tasks.
|
||||
Click on `Authorization` in the navigation and create a new one by selecting the user and the `admin` role.
|
||||
After successful creation, it should look like:
|
||||
|
||||

|
||||
|
||||
So you should now be able to add a new task:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:8089/api/add-task --data "task=My new task"
|
||||
```
|
||||
|
||||
which will report back the successful addition:
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Date: Mon, 04 Dec 2023 10:06:29 GMT
|
||||
Content-Length: 26
|
||||
|
||||
"task `My new task` added"
|
||||
```
|
||||
|
||||
Let's now retrieve the task list again:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:8089/api/tasks
|
||||
```
|
||||
|
||||
As you can see your new task ist listed. And since you're an `admin` now, you will always get an additional `create a new task on /api/add-task`:
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Date: Mon, 04 Dec 2023 10:08:38 GMT
|
||||
Content-Length: 62
|
||||
|
||||
{"tasks":["My new task","create a new task on /api/add-task"]}
|
||||
```
|
||||
|
@ -1,2 +1,5 @@
|
||||
Once you created the provider, it is listed in the providers overview.
|
||||
Activate it by selecting the tick with the tooltip *set as available*.
|
||||
Activate it by selecting the tick with the tooltip *set as available*.
|
||||
|
||||
If you deactivate a provider, your users with links to it will not be able to authenticate anymore.
|
||||
You can reactivate it and the logins will work again.
|
@ -65,3 +65,11 @@ import TestSetup from './_test_setup.mdx';
|
||||

|
||||
|
||||

|
||||
|
||||
## Optional: Add ZITADEL action to autofill userdata
|
||||
|
||||
<PrefillAction fields="firstname, lastname and email verified" provider="Okta"/>
|
||||
|
||||
```js reference
|
||||
https://github.com/zitadel/actions/blob/main/examples/okta_identity_provider.js
|
||||
```
|
||||
|
@ -76,7 +76,7 @@ curl --request POST \
|
||||
--header 'Authorization: Bearer '"$TOKEN"''\
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"token": "k50WQmDaPIazQDJsyKaEPaQPwgsytxqgQ3K1ifQeQtAmeQ"
|
||||
"idpIntentToken": "k50WQmDaPIazQDJsyKaEPaQPwgsytxqgQ3K1ifQeQtAmeQ"
|
||||
}'
|
||||
```
|
||||
|
||||
|
@ -42,7 +42,7 @@ Per default you will only search for users within the selected organization. If
|
||||
|
||||
## Configure roles
|
||||
|
||||
If you run a self hosted ZITADEL istance you can define your custom roles by overwriting the defaults.yaml
|
||||
If you run a self hosted ZITADEL instance you can define your custom roles by overwriting the defaults.yaml
|
||||
In the InternalAuthZ section you will find all the roles and which permissions they have.
|
||||
|
||||
Example:
|
||||
|
@ -77,7 +77,21 @@ You can also disable domain verification with DNS challenge in the [instance set
|
||||
1. Browse to your organization settings
|
||||
2. Select the menu entry **Verified domains**
|
||||
3. To start the domain verification click the domain name and a dialog will appear, where you can choose between DNS or HTTP challenge methods.
|
||||
4. For example, create a TXT record with your DNS provider for the used domain and click verify. ZITADEL will then proceed and check your DNS.
|
||||
|
||||
<img
|
||||
width="400px"
|
||||
src="/docs/img/console_verify_domain.png"
|
||||
alt="Select Organization"
|
||||
/>
|
||||
|
||||
4. For example, create a TXT record with your DNS provider for the used domain and click verify. ZITADEL will then proceed and check your DNS. Here are some useful links explaining how you can add TXT records for popular domain providers:
|
||||
|
||||
- [Cloudflare](https://www.zoho.com/mail/help/adminconsole/cloudflare.html#alink1)
|
||||
- [Squarespace](https://support.squarespace.com/hc/en-us/articles/205812388-Domain-verification-with-a-TXT-Record-alternative-method-)
|
||||
- [Name.com](https://www.name.com/support/articles/115004972547-adding-a-txt-record)
|
||||
- [EasyDNS](https://kb.easydns.com/knowledge/how-to-make-a-dns-entry/)
|
||||
- [DNS Made Easy](https://support.dnsmadeeasy.com/support/solutions/articles/47001001376-create-a-txt-record)
|
||||
|
||||
5. When the verification is successful you have the option to activate the domain by clicking **Set as primary**
|
||||
|
||||
:::caution
|
||||
|
@ -8,7 +8,11 @@ Users with the role IAM_OWNER can change the restrictions of their instance usin
|
||||
Currently, the following restrictions are available:
|
||||
|
||||
- *Disallow public organization registrations* - If restricted, only users with the role IAM_OWNERS can create new organizations. The endpoint */ui/login/register/org* returns HTTP status 404 on GET requests, and 409 on POST requests.
|
||||
- *[Coming soon](https://github.com/zitadel/zitadel/issues/6250): AllowedLanguages*
|
||||
- *AllowedLanguages* - The following rules apply if languages are restricted:
|
||||
- Only allowed languages are listed in the OIDC discovery endpoint */.well-kown/openid-configuration*.
|
||||
- Login UI texts are only rendered in allowed languages.
|
||||
- Notification message texts are only rendered in allowed languages.
|
||||
- Custom Texts can be created for disallowed languages as long as ZITADEL supports that language. Therefore, all texts can be customized before allowing a language.
|
||||
|
||||
Feature restrictions for an instance are intended to be configured by a user that is managed within that instance.
|
||||
However, if you are self-hosting and need to control your virtual instances usage, [read about the APIs for limits and quotas](/self-hosting/manage/usage_control) that are intended to be used by system users.
|
||||
|
@ -49,6 +49,17 @@ ZITADEL is available in the following languages
|
||||
- Russian (ru)
|
||||
- Dutch (nl)
|
||||
|
||||
A language is displayed based on your agent's language header. The default language is English.
|
||||
A language is displayed based on your agent's language header.
|
||||
If a users language header doesn't match any of the supported or [restricted](#restrict-languages) languages, the instances default language will be used.
|
||||
|
||||
If you need support for a specific language we highly encourage you to [contribute translation files](https://github.com/zitadel/zitadel/blob/main/CONTRIBUTING.md) for the missing language.
|
||||
|
||||
## Restrict Languages
|
||||
|
||||
If you only want to enable a subset of the supported languages, you can configure the languages you'd like to allow using the [restrictions API](./restrictions.md).
|
||||
The login UI and notification messages are only rendered in one of the allowed languages and fallback to the instances default language.
|
||||
Also, the instances OIDC discovery endpoint will only list the allowed languages in the *ui_locales_supported* field.
|
||||
|
||||
All language settings are also configurable in the consoles *Languages* instance settings.
|
||||
|
||||

|
||||
|
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