feat: SMTP Templates (#6932)

* feat: smtp templates poc

* feat: add isActive & ProviderType to SMTP backend

* feat: change providertype to uint32 and fix tests

* feat: minimal smtp provider component

* feat: woking on diiferent providers

* feat: keep working on providers

* feat: initial stepper for new provider

* fix: settings list and working on stepper

* feat: step 1 and 2 form inputs

* feat: starter for smtp test step

* fix: misspelled SMPT

* fix: remove tests for now

* feat: add tls toggle remove old google provider

* feat: working on add smtp and table

* fix: duplicated identifiers

* fix: settings list

* fix: add missing smtp config properties

* fix: add configID to smtp config table

* fix: working on listproviders

* feat: working in listSMTPConfigs

* fix: add count to listsmtpconfigs

* fix: getting empty results from listSMTPConfigs

* feat: table now shows real data

* fix: remaining styles for smtp-table

* fix: remove old notification-smtp-provider-component

* feat: delete smtp configuration

* feat: deactivate smtp config

* feat: replace isActive with state for smtp config

* feat: activate smtp config

* fix: remaining errors after main merge

* fix: list smtp providers panic and material mdc

* feat: refactor to only one provider component

* feat: current provider details view

* fix: refactor AddSMTPConfig and ChangeSMTPConfig

* fix: smtp config reduce issue

* fix: recover domain in NewIAMSMTPConfigWriteModel

* fix: add code needed by SetUpInstance

* fix: go tests and warn about passing context to InstanceAggregateFromWriteModel

* fix: i18n and add missing trans for fr, it, zh

* fix: add e2e tests

* docs: add smtp templates

* fix: remove provider_type, add description

* fix: remaining error from merge main

* fix: add @stebenz change for primary key

* fix: inactive placed after removed to prevent deleted configs to show as inactive

* fix: smtp provider id can be empty (migrated)

* feat: add mailchimp transactional template

* feat: add Brevo (Sendinblue) template

* feat: change brevo logo, add color to tls icon

* fix: queries use resourceowner, id must not be empty

* fix: deal with old smtp settings and tests

* fix: resourceOwner is the instanceID

* fix: remove aggregate_id, rename SMTPConfigByAggregateID with SMTPConfigActive

* fix: add tests for multiple configs with different IDs

* fix: conflict

* fix: remove notification-smtp-provider

* fix: add @peintnermax suggestions, rename module and fix e2e tests

* fix: remove material legacy modules

* fix: remove ctx as parameter for  InstanceAggregateFromWriteModel

* fix: add Id to SMTPConfigToPb

* fix:  change InstanceAggregateFromWriteModel to avoid linter errors

* fix import

* rm unused package-lock

* update yarn lock

---------

Co-authored-by: Elio Bischof <elio@zitadel.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
This commit is contained in:
Miguel Cabrerizo
2024-04-11 09:16:10 +02:00
committed by GitHub
parent e2f0cd034a
commit d229da6af7
93 changed files with 6359 additions and 6132 deletions

View File

@@ -159,6 +159,8 @@ export class AppComponent implements OnDestroy {
this.matIconRegistry.addSvgIcon('mdi_jwt', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/jwt.svg'));
this.matIconRegistry.addSvgIcon('mdi_smtp', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/mail.svg'));
this.matIconRegistry.addSvgIcon('mdi_symbol', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/symbol.svg'));
this.matIconRegistry.addSvgIcon(

View File

@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider.component';
describe('PasswordDialogComponent', () => {
let component: DialogAddSMSProviderComponent;
let fixture: ComponentFixture<DialogAddSMSProviderComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [DialogAddSMSProviderComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DialogAddSMSProviderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -10,7 +10,7 @@ import {
import { SMSProvider, TwilioConfig } from 'src/app/proto/generated/zitadel/settings_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ToastService } from 'src/app/services/toast.service';
import { PasswordDialogComponent } from '../password-dialog/password-dialog.component';
import { PasswordDialogSMSProviderComponent } from '../password-dialog-sms-provider/password-dialog-sms-provider.component';
enum SMSProviderType {
Twilio = 1,
@@ -73,7 +73,7 @@ export class DialogAddSMSProviderComponent {
}
public changeToken(): void {
const dialogRef = this.dialog.open(PasswordDialogComponent, {
const dialogRef = this.dialog.open(PasswordDialogSMSProviderComponent, {
width: '400px',
data: {
i18nTitle: 'SETTING.SMS.TWILIO.SETTOKEN',

View File

@@ -6,6 +6,7 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatIconModule } from '@angular/material/icon';
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';
@@ -16,10 +17,11 @@ import { InputModule } from '../../input/input.module';
import { WarnDialogModule } from '../../warn-dialog/warn-dialog.module';
import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component';
import { NotificationSMSProviderComponent } from './notification-sms-provider.component';
import { PasswordDialogSMSProviderComponent } from './password-dialog-sms-provider/password-dialog-sms-provider.component';
import { MatDialogModule } from '@angular/material/dialog';
@NgModule({
declarations: [NotificationSMSProviderComponent, DialogAddSMSProviderComponent],
declarations: [NotificationSMSProviderComponent, DialogAddSMSProviderComponent, PasswordDialogSMSProviderComponent],
imports: [
CommonModule,
CardModule,
@@ -34,9 +36,9 @@ import { MatDialogModule } from '@angular/material/dialog';
FormFieldModule,
WarnDialogModule,
MatSelectModule,
MatDialogModule,
MatProgressSpinnerModule,
MatSelectModule,
MatDialogModule,
TranslateModule,
],
exports: [NotificationSMSProviderComponent],

View File

@@ -1,6 +1,6 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { PasswordDialogComponent } from './password-dialog.component';
import { PasswordDialogComponent } from './password-dialog-sms-provider.component';
describe('PasswordDialogComponent', () => {
let component: PasswordDialogComponent;

View File

@@ -2,14 +2,14 @@ import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
@Component({
selector: 'cnsl-password-dialog',
templateUrl: './password-dialog.component.html',
styleUrls: ['./password-dialog.component.scss'],
selector: 'cnsl-password-dialog-sms-provider',
templateUrl: './password-dialog-sms-provider.component.html',
styleUrls: ['./password-dialog-sms-provider.component.scss'],
})
export class PasswordDialogComponent {
export class PasswordDialogSMSProviderComponent {
public password: string = '';
constructor(
public dialogRef: MatDialogRef<PasswordDialogComponent>,
public dialogRef: MatDialogRef<PasswordDialogSMSProviderComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
) {}

View File

@@ -1,70 +1,37 @@
<h2>{{ 'DESCRIPTIONS.SETTINGS.SMTP_PROVIDER.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'DESCRIPTIONS.SETTINGS.SMTP_PROVIDER.DESCRIPTION' | translate }}</p>
<h2>{{ 'SMTP.LIST.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'SMTP.LIST.DESCRIPTION' | translate }}</p>
<div class="spinner-wr">
<mat-spinner diameter="30" *ngIf="smtpLoading" color="primary"></mat-spinner>
<div class="cnsl-snmp-table-wrapper">
<cnsl-smtp-table></cnsl-smtp-table>
</div>
<cnsl-info-section
*ngIf="!smtpLoading && !form.valid"
class="info-section-warn"
[fitWidth]="true"
[type]="InfoSectionType.ALERT"
>{{ 'SETTING.SMTP.REQUIREDWARN' | translate }}</cnsl-info-section
>
<h2>{{ 'SMTP.CREATE.TITLE' | translate }}</h2>
<p class="cnsl-secondary-text">{{ 'SMTP.CREATE.DESCRIPTION' | translate }}</p>
<form (ngSubmit)="savePolicy()" [formGroup]="form" autocomplete="off">
<cnsl-form-field class="smtp-form-field" label="Sender Address" required="true">
<cnsl-label>{{ 'SETTING.SMTP.SENDERADDRESS' | translate }}</cnsl-label>
<input cnslInput name="senderAddress" formControlName="senderAddress" required />
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="Sender Name" required="true">
<cnsl-label>{{ 'SETTING.SMTP.SENDERNAME' | translate }}</cnsl-label>
<input cnslInput name="senderName" formControlName="senderName" required />
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="Reply-To Address">
<cnsl-label>{{ 'SETTING.SMTP.REPLYTOADDRESS' | translate }}</cnsl-label>
<input cnslInput name="senderReplyToAddress" formControlName="replyToAddress" />
</cnsl-form-field>
<mat-checkbox class="smtp-checkbox" formControlName="tls">
{{ 'SETTING.SMTP.TLS' | translate }}
</mat-checkbox>
<cnsl-form-field class="smtp-form-field" label="Host And Port" required="true">
<cnsl-label>{{ 'SETTING.SMTP.HOSTANDPORT' | translate }}</cnsl-label>
<input cnslInput name="hostAndPort" formControlName="hostAndPort" placeholder="smtp.mailtrap.io:2525" required />
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="User" required="true">
<cnsl-label>{{ 'SETTING.SMTP.USER' | translate }}</cnsl-label>
<input id="smtp-user" cnslInput name="smtp-user" autocomplete="smtp-user" formControlName="user" required />
</cnsl-form-field>
<button
class="set-password-btn"
[disabled]="(['iam.write'] | hasRole | async) === false || !hasSMTPConfig"
(click)="setSMTPPassword()"
type="button"
mat-stroked-button
data-e2e="add-smtp-password-button"
>
{{ 'SETTING.SMTP.SETPASSWORD' | translate }}
</button>
<div class="general-btn-container">
<button
class="save-button"
[disabled]="form.disabled"
(click)="savePolicy()"
color="primary"
type="submit"
mat-raised-button
data-e2e="save-smtp-settings-button"
<div class="new-smtp-wrapper">
<div *ngFor="let provider of providers">
<a
class="item card"
[routerLink]="['/instance', 'smtpprovider', provider.routerLinkElement, 'create']"
*ngIf="provider.name !== 'generic'"
>
{{ 'ACTIONS.SAVE' | translate }}
</button>
<img class="smtp-logo" src="{{ provider.image }}" alt="{{ provider.name }}" />
<div class="text-container">
<span class="title">{{ provider.name | titlecase }} </span>
</div>
</a>
<a
class="item card"
[routerLink]="['/instance', 'smtpprovider', provider.routerLinkElement, 'create']"
*ngIf="provider.name === 'generic'"
>
<div class="smtp-icon">
<mat-icon class="icon" svgIcon="mdi_smtp" />
</div>
<div class="text-container">
<span class="title">Generic SMTP</span>
</div>
</a>
</div>
</form>
</div>

View File

@@ -1,32 +1,113 @@
.spinner-wr {
margin: 0.5rem 0;
}
@use '@angular/material' as mat;
.smtp-form-field,
.info-section-warn {
max-width: 400px;
display: block;
}
@mixin smtp-settings-theme($theme) {
$primary: map-get($theme, primary);
$primary-color: mat.get-color-from-palette($primary, 500);
$is-dark-theme: map-get($theme, is-dark);
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
.info-section-warn {
margin-bottom: 0.5rem;
}
.smtp-checkbox {
max-width: 400px;
display: block;
margin: 1rem 0;
}
.set-password-btn {
margin-bottom: 1rem;
}
.general-btn-container {
display: flex;
justify-content: flex-start;
.save-button {
.cnsl-smtp-table-wrapper {
display: block;
}
.new-smtp-wrapper {
display: grid;
row-gap: 1.5rem;
column-gap: 1.5rem;
box-sizing: border-box;
width: 100%;
grid-template-columns: 1fr;
@media only screen and (min-width: 700px) {
grid-template-columns: 1fr 1fr;
}
@media only screen and (min-width: 1000px) {
grid-template-columns: 1fr 1fr 1fr;
}
@media only screen and (min-width: 1300px) {
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.item {
position: relative;
z-index: 100;
display: flex;
text-decoration: none;
cursor: pointer;
padding-top: 1rem;
padding-right: 1rem;
padding-bottom: 1rem;
padding-left: 1rem;
border-radius: 0.5rem;
box-sizing: border-box;
transition: box-shadow 0.1s ease-in;
align-items: center;
color: map-get($foreground, text);
.coming-soon-label {
position: absolute;
top: 0;
right: 1rem;
transform: translateY(-50%);
width: fit-content;
}
&:hover {
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.12);
}
.smtp-logo {
margin-right: 1rem;
height: 36px;
width: 36px;
&.apple {
margin-bottom: 4px;
}
&.dark {
display: if($is-dark-theme, block, none);
}
&.light {
display: if($is-dark-theme, none, block);
}
}
.smtp-icon {
margin-right: 1rem;
display: flex;
justify-content: center;
align-items: center;
height: 36px;
width: 36px;
.icon {
font-size: 2.25rem;
height: 2.25rem;
width: 2.25rem;
}
}
.text-container {
display: flex;
flex-direction: column;
.title {
}
}
&.coming-soon {
filter: grayscale(1);
cursor: not-allowed;
&:hover {
box-shadow: none;
}
}
}
}
}

View File

@@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NotificationSMTPProviderComponent } from './notification-smtp-provider.component';
describe('NotificationSMTPProviderComponent', () => {
describe('IdpSettingsComponent', () => {
let component: NotificationSMTPProviderComponent;
let fixture: ComponentFixture<NotificationSMTPProviderComponent>;

View File

@@ -1,22 +1,9 @@
import { Component, Input, OnInit } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { take } from 'rxjs';
import {
AddSMTPConfigRequest,
AddSMTPConfigResponse,
UpdateSMTPConfigPasswordRequest,
UpdateSMTPConfigRequest,
UpdateSMTPConfigResponse,
} from 'src/app/proto/generated/zitadel/admin_pb';
import { Component, Injector, Input, OnInit, Type } from '@angular/core';
import { AdminService } from 'src/app/services/admin.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ToastService } from 'src/app/services/toast.service';
import { requiredValidator } from '../../form-field/validators/validators';
import { ManagementService } from 'src/app/services/mgmt.service';
import { InfoSectionType } from '../../info-section/info-section.component';
import { PasswordDialogComponent } from '../notification-sms-provider/password-dialog/password-dialog.component';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
import { SMTPKnownProviders } from '../../smtp-provider/known-smtp-providers-settings';
@Component({
selector: 'cnsl-notification-smtp-provider',
@@ -25,151 +12,21 @@ import { PolicyComponentServiceType } from '../policy-component-types.enum';
})
export class NotificationSMTPProviderComponent implements OnInit {
@Input() public serviceType!: PolicyComponentServiceType;
public service!: ManagementService | AdminService;
public smtpLoading: boolean = false;
public PolicyComponentServiceType: any = PolicyComponentServiceType;
public providers = SMTPKnownProviders;
public form!: UntypedFormGroup;
public InfoSectionType: any = InfoSectionType;
public hasSMTPConfig: boolean = false;
// show available providers
constructor(
private service: AdminService,
private dialog: MatDialog,
private toast: ToastService,
private fb: UntypedFormBuilder,
private authService: GrpcAuthService,
) {
this.form = this.fb.group({
senderAddress: [{ disabled: true, value: '' }, [requiredValidator]],
senderName: [{ disabled: true, value: '' }, [requiredValidator]],
replyToAddress: [{ disabled: true, value: '' }],
tls: [{ disabled: true, value: true }, [requiredValidator]],
hostAndPort: [{ disabled: true, value: '' }, [requiredValidator]],
user: [{ disabled: true, value: '' }, [requiredValidator]],
});
}
constructor(private injector: Injector) {}
ngOnInit(): void {
this.fetchData();
this.authService
.isAllowed(['iam.write'])
.pipe(take(1))
.subscribe((allowed) => {
if (allowed) {
this.form.enable();
}
});
}
private fetchData(): void {
this.smtpLoading = true;
this.service
.getSMTPConfig()
.then((smtpConfig) => {
this.smtpLoading = false;
if (smtpConfig.smtpConfig) {
this.hasSMTPConfig = true;
this.form.patchValue(smtpConfig.smtpConfig);
this.form.patchValue({ ['hostAndPort']: smtpConfig.smtpConfig.host });
}
})
.catch((error) => {
this.smtpLoading = false;
if (error && error.code === 5) {
console.log(error);
this.hasSMTPConfig = false;
}
});
}
private updateData(): Promise<UpdateSMTPConfigResponse.AsObject | AddSMTPConfigResponse> {
if (this.hasSMTPConfig) {
const req = new UpdateSMTPConfigRequest();
req.setHost(this.hostAndPort?.value ?? '');
req.setSenderAddress(this.senderAddress?.value ?? '');
req.setSenderName(this.senderName?.value ?? '');
req.setReplyToAddress(this.replyToAddress?.value ?? '');
req.setTls(this.tls?.value ?? false);
req.setUser(this.user?.value ?? '');
return this.service.updateSMTPConfig(req);
} else {
const req = new AddSMTPConfigRequest();
req.setHost(this.hostAndPort?.value ?? '');
req.setSenderAddress(this.senderAddress?.value ?? '');
req.setSenderName(this.senderName?.value ?? '');
req.setReplyToAddress(this.replyToAddress?.value ?? '');
req.setTls(this.tls?.value ?? false);
req.setUser(this.user?.value ?? '');
return this.service.addSMTPConfig(req);
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
break;
}
}
public savePolicy(): void {
this.updateData()
.then(() => {
this.toast.showInfo('SETTING.SMTP.SAVED', true);
setTimeout(() => {
this.fetchData();
}, 2000);
})
.catch((error: unknown) => {
this.toast.showError(error);
});
}
public setSMTPPassword(): void {
const dialogRef = this.dialog.open(PasswordDialogComponent, {
width: '400px',
data: {
i18nTitle: 'SETTING.SMTP.SETPASSWORD',
i18nLabel: 'SETTING.SMTP.PASSWORD',
},
});
dialogRef.afterClosed().subscribe((password: string) => {
if (password) {
const passwordReq = new UpdateSMTPConfigPasswordRequest();
passwordReq.setPassword(password);
this.service
.updateSMTPConfigPassword(passwordReq)
.then(() => {
this.toast.showInfo('SETTING.SMTP.PASSWORDSET', true);
})
.catch((error) => {
this.toast.showError(error);
});
}
});
}
public get senderAddress(): AbstractControl | null {
return this.form.get('senderAddress');
}
public get senderName(): AbstractControl | null {
return this.form.get('senderName');
}
public get replyToAddress(): AbstractControl | null {
return this.form.get('replyToAddress');
}
public get tls(): AbstractControl | null {
return this.form.get('tls');
}
public get user(): AbstractControl | null {
return this.form.get('user');
}
public get hostAndPort(): AbstractControl | null {
return this.form.get('hostAndPort');
}
}

View File

@@ -1,43 +1,32 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { RouterModule } from '@angular/router';
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 { InfoSectionModule } from '../../info-section/info-section.module';
import { InputModule } from '../../input/input.module';
import { WarnDialogModule } from '../../warn-dialog/warn-dialog.module';
import { PasswordDialogComponent } from '../notification-sms-provider/password-dialog/password-dialog.component';
import { NotificationSMTPProviderComponent } from './notification-smtp-provider.component';
import { MatDialogModule } from '@angular/material/dialog';
import { InputModule } from '../../input/input.module';
import { FormFieldModule } from '../../form-field/form-field.module';
import { SMTPTableModule } from '../../smtp-table/smtp-table.module';
import { MatButtonModule } from '@angular/material/button';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
@NgModule({
declarations: [NotificationSMTPProviderComponent, PasswordDialogComponent],
declarations: [NotificationSMTPProviderComponent],
imports: [
CommonModule,
CardModule,
InfoSectionModule,
FormsModule,
ReactiveFormsModule,
HasRolePipeModule,
MatButtonModule,
MatCheckboxModule,
InputModule,
MatIconModule,
FormFieldModule,
WarnDialogModule,
MatSelectModule,
CommonModule,
MatButtonModule,
CardModule,
MatIconModule,
SMTPTableModule,
RouterModule,
HasRolePipeModule,
MatProgressSpinnerModule,
MatSelectModule,
TranslateModule,
MatDialogModule,
],
exports: [NotificationSMTPProviderComponent],
})

View File

@@ -14,7 +14,6 @@ import { LoginTextsPolicyModule } from '../policies/login-texts/login-texts.modu
import { MessageTextsPolicyModule } from '../policies/message-texts/message-texts.module';
import { NotificationPolicyModule } from '../policies/notification-policy/notification-policy.module';
import { NotificationSMSProviderModule } from '../policies/notification-sms-provider/notification-sms-provider.module';
import { NotificationSMTPProviderModule } from '../policies/notification-smtp-provider/notification-smtp-provider.module';
import { OIDCConfigurationModule } from '../policies/oidc-configuration/oidc-configuration.module';
import { PasswordComplexityPolicyModule } from '../policies/password-complexity-policy/password-complexity-policy.module';
import { PasswordLockoutPolicyModule } from '../policies/password-lockout-policy/password-lockout-policy.module';
@@ -28,7 +27,9 @@ import FailedEventsModule from '../failed-events/failed-events.module';
import IamViewsModule from '../iam-views/iam-views.module';
import EventsModule from '../events/events.module';
import { OrgTableModule } from '../org-table/org-table.module';
import { NotificationSMTPProviderModule } from '../policies/notification-smtp-provider/notification-smtp-provider.module';
import { FeaturesComponent } from 'src/app/components/features/features.component';
import OrgListModule from 'src/app/pages/org-list/org-list.module';
@NgModule({
declarations: [SettingsListComponent],
@@ -44,12 +45,14 @@ import { FeaturesComponent } from 'src/app/components/features/features.componen
LanguageSettingsModule,
NotificationPolicyModule,
IdpSettingsModule,
NotificationSMTPProviderModule,
PrivacyPolicyModule,
MessageTextsPolicyModule,
SecurityPolicyModule,
DomainsModule,
LoginTextsPolicyModule,
OrgTableModule,
OrgListModule,
DomainPolicyModule,
TranslateModule,
HasRolePipeModule,

View File

@@ -0,0 +1,174 @@
export interface AmazonRegionsEndpoints {
'US East (Ohio)': string;
'US East (N. Virginia)': string;
'US West (N. California)': string;
'US West (Oregon)': string;
'Asia Pacific (Mumbai)': string;
'Asia Pacific (Osaka)': string;
'Asia Pacific (Seoul)': string;
'Asia Pacific (Singapore)': string;
'Asia Pacific (Sydney)': string;
'Asia Pacific (Tokyo)': string;
'Canada (Central)': string;
'Europe (Frankfurt)': string;
'Europe (London)': string;
'Europe (Paris)': string;
'Europe (Stockholm)': string;
'South America (São Paulo)': string;
}
const amazonEndpoints = {
'US East (Ohio)': 'email-smtp.us-east-2.amazonaws.com',
'US East (N. Virginia)': 'email-smtp.us-east-1.amazonaws.com',
'US West (N. California)': 'email-smtp.us-west-1.amazonaws.com',
'US West (Oregon)': 'email-smtp.us-west-2.amazonaws.com',
'Asia Pacific (Mumbai)': 'email-smtp.ap-south-1.amazonaws.com',
'Asia Pacific (Osaka)': 'email-smtp.ap-northeast-3.amazonaws.com',
'Asia Pacific (Seoul)': 'email-smtp.ap-northeast-2.amazonaws.com',
'Asia Pacific (Singapore)': 'email-smtp.ap-southeast-1.amazonaws.com',
'Asia Pacific (Sydney)': 'email-smtp.ap-southeast-2.amazonaws.com',
'Asia Pacific (Tokyo)': 'email-smtp.ap-northeast-1.amazonaws.com',
'Canada (Central)': 'email-smtp.ca-central-1.amazonaws.com',
'Europe (Frankfurt)': 'email-smtp.eu-central-1.amazonaws.com',
'Europe (Ireland)': 'email-smtp.eu-west-1.amazonaws.com',
'Europe (London)': 'email-smtp.eu-west-2.amazonaws.com',
'Europe (Paris)': 'email-smtp.eu-west-3.amazonaws.com',
'Europe (Stockholm)': 'email-smtp.eu-north-1.amazonaws.com',
'South America (São Paulo)': 'email-smtp.sa-east-1.amazonaws.com',
};
export interface ProviderDefaultSettings {
name: string;
regions?: AmazonRegionsEndpoints;
multiHostsLabel?: string;
requiredTls: boolean;
host?: string;
unencryptedPort?: number;
encryptedPort?: number;
user: {
value: string;
placeholder: string;
};
password: {
value: string;
placeholder: string;
};
image?: string;
routerLinkElement: string;
}
export const AmazonSESDefaultSettings: ProviderDefaultSettings = {
name: 'amazon SES',
regions: amazonEndpoints,
multiHostsLabel: 'Choose your region',
requiredTls: true,
encryptedPort: 587,
user: { value: '', placeholder: 'your Amazon SES credentials for this region' },
password: { value: '', placeholder: 'your Amazon SES credentials for this region' },
image: './assets/images/smtp/aws-ses.svg',
routerLinkElement: 'aws-ses',
};
export const GoogleDefaultSettings: ProviderDefaultSettings = {
name: 'google',
requiredTls: true,
host: 'smtp.gmail.com',
unencryptedPort: 587,
encryptedPort: 587,
user: { value: '', placeholder: 'your complete Google Workspace email address' },
password: { value: '', placeholder: 'your complete Google Workspace password' },
image: './assets/images/smtp/google.png',
routerLinkElement: 'google',
};
export const MailgunDefaultSettings: ProviderDefaultSettings = {
name: 'mailgun',
requiredTls: false,
host: 'smtp.mailgun.org',
unencryptedPort: 587,
encryptedPort: 465,
user: { value: '', placeholder: 'postmaster@YOURDOMAIN' },
password: { value: '', placeholder: 'Your mailgun smtp password' },
image: './assets/images/smtp/mailgun.svg',
routerLinkElement: 'mailgun',
};
export const MailjetDefaultSettings: ProviderDefaultSettings = {
name: 'mailjet',
requiredTls: false,
host: 'in-v3.mailjet.com',
unencryptedPort: 587,
encryptedPort: 465,
user: { value: '', placeholder: 'Your Mailjet API key' },
password: { value: '', placeholder: 'Your Mailjet Secret key' },
image: './assets/images/smtp/mailjet.svg',
routerLinkElement: 'mailjet',
};
export const PostmarkDefaultSettings: ProviderDefaultSettings = {
name: 'postmark',
requiredTls: false,
host: 'smtp.postmarkapp.com',
unencryptedPort: 587,
encryptedPort: 587,
user: { value: '', placeholder: 'Your Server API token' },
password: { value: '', placeholder: 'Your Server API token' },
image: './assets/images/smtp/postmark.png',
routerLinkElement: 'postmark',
};
export const SendgridDefaultSettings: ProviderDefaultSettings = {
name: 'sendgrid',
requiredTls: false,
host: 'smtp.sendgrid.net',
unencryptedPort: 587,
encryptedPort: 465,
user: { value: 'apikey', placeholder: '' },
password: { value: '', placeholder: ' Your SendGrid API Key' },
image: './assets/images/smtp/sendgrid.png',
routerLinkElement: 'sendgrid',
};
export const MailchimpDefaultSettings: ProviderDefaultSettings = {
name: 'mailchimp',
requiredTls: false,
host: 'smtp.mandrillapp.com',
unencryptedPort: 587,
encryptedPort: 465,
user: { value: '', placeholder: 'Your Mailchimp primary contact email' },
password: { value: '', placeholder: 'Your Mailchimp Transactional API key' },
image: './assets/images/smtp/mailchimp.svg',
routerLinkElement: 'mailchimp',
};
export const BrevoDefaultSettings: ProviderDefaultSettings = {
name: 'brevo',
requiredTls: false,
host: 'smtp-relay.sendinblue.com',
unencryptedPort: 587,
encryptedPort: 465,
user: { value: '', placeholder: 'Your SMTP login email address' },
password: { value: '', placeholder: 'Your SMTP key' },
image: './assets/images/smtp/brevo.svg',
routerLinkElement: 'brevo',
};
export const GenericDefaultSettings: ProviderDefaultSettings = {
name: 'generic',
requiredTls: false,
user: { value: '', placeholder: 'your SMTP user' },
password: { value: '', placeholder: 'your SMTP password' },
routerLinkElement: 'generic',
};
export const SMTPKnownProviders = [
AmazonSESDefaultSettings,
BrevoDefaultSettings,
// GoogleDefaultSettings,
MailgunDefaultSettings,
MailchimpDefaultSettings,
MailjetDefaultSettings,
PostmarkDefaultSettings,
SendgridDefaultSettings,
GenericDefaultSettings,
];

View File

@@ -0,0 +1,39 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SMTPProviderComponent } from './smtp-provider.component';
const types = [
{ path: 'aws-ses', component: SMTPProviderComponent },
{ path: 'generic', component: SMTPProviderComponent },
{ path: 'google', component: SMTPProviderComponent },
{ path: 'mailgun', component: SMTPProviderComponent },
{ path: 'postmark', component: SMTPProviderComponent },
{ path: 'sendgrid', component: SMTPProviderComponent },
{ path: 'mailjet', component: SMTPProviderComponent },
{ path: 'mailchimp', component: SMTPProviderComponent },
{ path: 'brevo', component: SMTPProviderComponent },
];
const routes: Routes = types.map((value) => {
return {
path: value.path,
children: [
{
path: 'create',
component: value.component,
},
],
};
});
routes.push({
path: ':id',
component: SMTPProviderComponent,
});
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class SMTPProvidersRoutingModule {}

View File

@@ -0,0 +1,144 @@
<cnsl-create-layout
title="{{
id ? ('SMTP.DETAIL.TITLE' | translate) : ('SMTP.CREATE.STEPS.TITLE' | translate: { value: providerDefaultSetting.name })
}}"
[createSteps]="2"
[currentCreateStep]="currentCreateStep"
(closed)="close()"
>
<div class="wizard-header">
<img
class="smtp-logo"
src="{{ providerDefaultSetting.image }}"
alt="{{ providerDefaultSetting.name }}"
*ngIf="providerDefaultSetting.name !== 'generic'"
/>
<div class="smtp-icon" *ngIf="providerDefaultSetting.name === 'generic'">
<mat-icon class="icon" svgIcon="mdi_smtp" alt="providerDefaultSetting.name" />
</div>
<h2>
{{
!id
? ('SMTP.CREATE.STEPS.CREATE_DESC_TITLE' | translate: { value: providerDefaultSetting.name | titlecase })
: ('SMTP.CREATE.STEPS.CURRENT_DESC_TITLE' | translate)
}}
</h2>
</div>
<mat-progress-bar class="progress-bar" color="primary" *ngIf="smtpLoading" mode="indeterminate"></mat-progress-bar>
<mat-horizontal-stepper
class="stepper {{ 'last-edited-step-' + stepper.selectedIndex }}"
linear
#stepper
labelPosition="bottom"
(selectionChange)="changeStep($event)"
>
<mat-step [editable]="true">
<ng-template matStepLabel>{{ 'SMTP.CREATE.STEPS.PROVIDER_SETTINGS' | translate }}</ng-template>
<form [formGroup]="firstFormGroup" autocomplete="off">
<mat-checkbox class="smtp-checkbox" formControlName="tls" (change)="toggleTLS($event)" data-e2e="tls-checkbox">
{{ 'SETTING.SMTP.TLS' | translate }}
</mat-checkbox>
<cnsl-form-field class="smtp-form-field" *ngIf="providerDefaultSetting.regions">
<cnsl-label>{{ providerDefaultSetting.multiHostsLabel }}</cnsl-label>
<mat-select formControlName="region">
<mat-option *ngFor="let region of providerDefaultSetting.regions | keyvalue" [value]="region.value">
{{ region.key }}
</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="Description">
<cnsl-label>{{ 'SETTING.SMTP.DESCRIPTION' | translate }}</cnsl-label>
<input cnslInput name="description" formControlName="description" placeholder="description" />
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="Host And Port">
<cnsl-label>{{ 'SETTING.SMTP.HOSTANDPORT' | translate }}</cnsl-label>
<input cnslInput name="hostAndPort" formControlName="hostAndPort" placeholder="host:port" required />
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="User">
<cnsl-label>{{ 'SETTING.SMTP.USER' | translate }}</cnsl-label>
<input
id="smtp-user"
cnslInput
name="smtp-user"
autocomplete="smtp-user"
formControlName="user"
placeholder="{{ providerDefaultSetting.user.placeholder }}"
required
/>
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="Password">
<cnsl-label>{{ 'SETTING.SMTP.PASSWORD' | translate }}</cnsl-label>
<input
id="smtp-password"
cnslInput
name="smtp-password"
autocomplete="off webauthn"
formControlName="password"
placeholder="{{ hasSMTPConfig ? '****************' : providerDefaultSetting.password.placeholder }}"
type="password"
required="{{ !hasSMTPConfig }}"
/>
</cnsl-form-field>
</form>
<div class="smtp-create-actions">
<button
mat-raised-button
[disabled]="firstFormGroup.invalid"
color="primary"
matStepperNext
data-e2e="continue-button"
>
{{ 'ACTIONS.CONTINUE' | translate }}
</button>
</div>
</mat-step>
<mat-step [editable]="true">
<form [formGroup]="secondFormGroup">
<ng-template matStepLabel>{{ 'SMTP.CREATE.STEPS.SENDER_SETTINGS' | translate }}</ng-template>
<cnsl-form-field class="smtp-form-field" label="Sender Address">
<cnsl-label>{{ 'SETTING.SMTP.SENDERADDRESS' | translate }}</cnsl-label>
<input cnslInput name="senderAddress" formControlName="senderAddress" placeholder="sender@example.com" required />
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="Sender Name">
<cnsl-label>{{ 'SETTING.SMTP.SENDERNAME' | translate }}</cnsl-label>
<input cnslInput name="senderName" formControlName="senderName" placeholder="Zitadel" required />
</cnsl-form-field>
<cnsl-form-field class="smtp-form-field" label="Reply-To Address">
<cnsl-label>{{ 'SETTING.SMTP.REPLYTOADDRESS' | translate }}</cnsl-label>
<input cnslInput name="senderReplyToAddress" formControlName="replyToAddress" placeholder="replyto@example.com" />
</cnsl-form-field>
</form>
<div class="smtp-create-actions">
<button mat-stroked-button matStepperPrevious class="bck-button">{{ 'ACTIONS.BACK' | translate }}</button>
<button
mat-raised-button
class="create-button"
color="primary"
data-e2e="create-button"
(click)="savePolicy()"
[disabled]="
firstFormGroup.invalid || secondFormGroup.invalid || (['iam.policy.write'] | hasRole | async) === false
"
>
{{ !hasSMTPConfig ? ('ACTIONS.CREATE' | translate) : ('ACTIONS.SAVE' | translate) }}
</button>
</div>
</mat-step>
<ng-template matStepperIcon="edit">
<mat-icon>check</mat-icon>
</ng-template>
</mat-horizontal-stepper>
</cnsl-create-layout>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SMTPProviderComponent } from './smtp-provider.component';
describe('SMTPProviderSendgridComponent', () => {
let component: SMTPProviderComponent;
let fixture: ComponentFixture<SMTPProviderComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [SMTPProviderComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SMTPProviderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,278 @@
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
import { Location } from '@angular/common';
import { Component } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Subject } from 'rxjs';
import { StepperSelectionEvent } from '@angular/cdk/stepper';
import { Options } from 'src/app/proto/generated/zitadel/idp_pb';
import { requiredValidator } from '../form-field/validators/validators';
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
import {
AddSMTPConfigRequest,
AddSMTPConfigResponse,
UpdateSMTPConfigRequest,
UpdateSMTPConfigResponse,
} from 'src/app/proto/generated/zitadel/admin_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ToastService } from 'src/app/services/toast.service';
import { ActivatedRoute, Router } from '@angular/router';
import { MatCheckboxChange } from '@angular/material/checkbox';
import {
AmazonSESDefaultSettings,
BrevoDefaultSettings,
GenericDefaultSettings,
GoogleDefaultSettings,
MailchimpDefaultSettings,
MailgunDefaultSettings,
MailjetDefaultSettings,
PostmarkDefaultSettings,
ProviderDefaultSettings,
SendgridDefaultSettings,
} from './known-smtp-providers-settings';
@Component({
selector: 'cnsl-smtp-provider',
templateUrl: './smtp-provider.component.html',
styleUrls: ['./smtp-provider.scss'],
})
export class SMTPProviderComponent {
public showOptional: boolean = false;
public options: Options = new Options().setIsCreationAllowed(true).setIsLinkingAllowed(true);
public id: string = '';
public providerDefaultSetting: ProviderDefaultSettings = GenericDefaultSettings;
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
public smtpLoading: boolean = false;
public hasSMTPConfig: boolean = false;
public updateClientSecret: boolean = false;
// stepper
public currentCreateStep: number = 1;
public requestRedirectValuesSubject$: Subject<void> = new Subject();
public firstFormGroup!: UntypedFormGroup;
public secondFormGroup!: UntypedFormGroup;
constructor(
private service: AdminService,
private _location: Location,
private fb: UntypedFormBuilder,
private toast: ToastService,
private router: Router,
private route: ActivatedRoute,
) {
this.route.parent?.url.subscribe((urlPath) => {
const providerName = urlPath[urlPath.length - 1].path;
switch (providerName) {
case 'aws-ses':
this.providerDefaultSetting = AmazonSESDefaultSettings;
break;
case 'google':
this.providerDefaultSetting = GoogleDefaultSettings;
break;
case 'mailgun':
this.providerDefaultSetting = MailgunDefaultSettings;
break;
case 'mailjet':
this.providerDefaultSetting = MailjetDefaultSettings;
break;
case 'postmark':
this.providerDefaultSetting = PostmarkDefaultSettings;
break;
case 'sendgrid':
this.providerDefaultSetting = SendgridDefaultSettings;
break;
case 'mailchimp':
this.providerDefaultSetting = MailchimpDefaultSettings;
break;
case 'brevo':
this.providerDefaultSetting = BrevoDefaultSettings;
break;
}
this.firstFormGroup = this.fb.group({
description: [this.providerDefaultSetting.name],
tls: [{ value: this.providerDefaultSetting.requiredTls, disabled: this.providerDefaultSetting.requiredTls }],
region: [''],
hostAndPort: [
this.providerDefaultSetting?.host
? `${this.providerDefaultSetting?.host}:${this.providerDefaultSetting?.unencryptedPort}`
: '',
],
user: [this.providerDefaultSetting?.user.value || ''],
password: [this.providerDefaultSetting?.password.value || ''],
});
this.secondFormGroup = this.fb.group({
senderAddress: ['', [requiredValidator]],
senderName: ['', [requiredValidator]],
replyToAddress: [''],
});
this.region?.valueChanges.subscribe((region: string) => {
this.hostAndPort?.setValue(
`${region}:${
this.tls ? this.providerDefaultSetting?.encryptedPort : this.providerDefaultSetting?.unencryptedPort
}`,
);
});
if (!this.router.url.endsWith('/create')) {
this.id = this.route.snapshot.paramMap.get('id') || '';
if (this.id) {
this.fetchData(this.id);
}
}
});
}
public changeStep(event: StepperSelectionEvent): void {
this.currentCreateStep = event.selectedIndex + 1;
if (event.selectedIndex >= 2) {
this.requestRedirectValuesSubject$.next();
}
}
public close(): void {
this._location.back();
}
public toggleTLS(event: MatCheckboxChange) {
if (this.providerDefaultSetting.host) {
this.hostAndPort?.setValue(
`${this.providerDefaultSetting?.host}:${
event.checked ? this.providerDefaultSetting?.encryptedPort : this.providerDefaultSetting?.unencryptedPort
}`,
);
}
}
private fetchData(id: string): void {
this.smtpLoading = true;
this.service
.getSMTPConfigById(id)
.then((data) => {
this.smtpLoading = false;
if (data.smtpConfig) {
this.hasSMTPConfig = true;
this.firstFormGroup.patchValue({
['description']: data.smtpConfig.description,
['tls']: data.smtpConfig.tls,
['hostAndPort']: data.smtpConfig.host,
['user']: data.smtpConfig.user,
});
this.secondFormGroup.patchValue({
['senderAddress']: data.smtpConfig.senderAddress,
['senderName']: data.smtpConfig.senderName,
['replyToAddress']: data.smtpConfig.replyToAddress,
});
}
})
.catch((error) => {
this.smtpLoading = false;
if (error && error.code === 5) {
this.hasSMTPConfig = false;
}
});
}
private updateData(): Promise<UpdateSMTPConfigResponse.AsObject | AddSMTPConfigResponse> {
if (this.hasSMTPConfig) {
const req = new UpdateSMTPConfigRequest();
req.setId(this.id);
req.setDescription(this.description?.value || '');
req.setTls(this.tls?.value ?? false);
if (this.hostAndPort && this.hostAndPort.value) {
req.setHost(this.hostAndPort.value);
}
if (this.user && this.user.value) {
req.setUser(this.user.value);
}
if (this.password && this.password.value) {
req.setPassword(this.password.value);
}
if (this.senderAddress && this.senderAddress.value) {
req.setSenderAddress(this.senderAddress.value);
}
if (this.senderName && this.senderName.value) {
req.setSenderName(this.senderName.value);
}
if (this.replyToAddress && this.replyToAddress.value) {
req.setReplyToAddress(this.replyToAddress.value);
}
return this.service.updateSMTPConfig(req);
} else {
const req = new AddSMTPConfigRequest();
req.setDescription(this.description?.value ?? '');
req.setHost(this.hostAndPort?.value ?? '');
req.setSenderAddress(this.senderAddress?.value ?? '');
req.setSenderName(this.senderName?.value ?? '');
req.setReplyToAddress(this.replyToAddress?.value ?? '');
req.setTls(this.tls?.value ?? false);
req.setUser(this.user?.value ?? '');
req.setPassword(this.password?.value ?? '');
return this.service.addSMTPConfig(req);
}
}
public savePolicy(): void {
this.updateData()
.then(() => {
this.toast.showInfo('SETTING.SMTP.SAVED', true);
setTimeout(() => {
this.close();
}, 2000);
})
.catch((error: unknown) => {
if (`${error}`.includes('No changes')) {
this.toast.showInfo('SETTING.SMTP.NOCHANGES', true);
setTimeout(() => {
this.close();
}, 2000);
} else {
this.toast.showError(error);
}
});
}
public get description(): AbstractControl | null {
return this.firstFormGroup.get('description');
}
public get tls(): AbstractControl | null {
return this.firstFormGroup.get('tls');
}
public get region(): AbstractControl | null {
return this.firstFormGroup.get('region');
}
public get hostAndPort(): AbstractControl | null {
return this.firstFormGroup.get('hostAndPort');
}
public get user(): AbstractControl | null {
return this.firstFormGroup.get('user');
}
public get password(): AbstractControl | null {
return this.firstFormGroup.get('password');
}
public get senderAddress(): AbstractControl | null {
return this.secondFormGroup.get('senderAddress');
}
public get senderName(): AbstractControl | null {
return this.secondFormGroup.get('senderName');
}
public get replyToAddress(): AbstractControl | null {
return this.secondFormGroup.get('replyToAddress');
}
}

View File

@@ -0,0 +1,51 @@
import { CommonModule, TitleCasePipe } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
import { InputModule } from 'src/app/modules/input/input.module';
import { MatStepperModule } from '@angular/material/stepper';
import { CardModule } from '../card/card.module';
import { CreateLayoutModule } from '../create-layout/create-layout.module';
import { InfoSectionModule } from '../info-section/info-section.module';
import { ProviderOptionsModule } from '../provider-options/provider-options.module';
import { StringListModule } from '../string-list/string-list.module';
import { SMTPProvidersRoutingModule } from './smtp-provider-routing.module';
import { SMTPProviderComponent } from './smtp-provider.component';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
import { MatButtonModule } from '@angular/material/button';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSelectModule } from '@angular/material/select';
import { MatChipsModule } from '@angular/material/chips';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
@NgModule({
declarations: [SMTPProviderComponent],
imports: [
SMTPProvidersRoutingModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
CreateLayoutModule,
StringListModule,
InfoSectionModule,
InputModule,
MatButtonModule,
MatProgressBarModule,
MatSelectModule,
MatIconModule,
MatChipsModule,
CardModule,
MatCheckboxModule,
MatTooltipModule,
MatStepperModule,
TranslateModule,
ProviderOptionsModule,
HasRolePipeModule,
MatProgressSpinnerModule,
],
})
export default class SMTPProviderModule {}

View File

@@ -0,0 +1,71 @@
@use '@angular/material' as mat;
@mixin smtp-provider-theme($theme) {
$is-dark-theme: map-get($theme, is-dark);
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
.stepper {
background: inherit !important;
margin: 0 -1.5rem;
}
.smtp-create-actions {
margin-top: 2rem;
display: flex;
align-items: center;
justify-content: space-between;
.bck-button {
margin-right: 1rem;
}
.create-button {
padding: 0.5rem 4rem;
}
}
.smtp-form-field,
.info-section-warn {
max-width: 400px;
display: block;
}
.wizard-header {
display: flex;
align-items: center;
.smtp-logo {
margin-right: 1rem;
height: 48px;
width: 48px;
flex-shrink: 0;
}
.smtp-icon {
margin-right: 1rem;
display: flex;
justify-content: center;
align-items: center;
height: 36px;
width: 36px;
.icon {
font-size: 2.25rem;
height: 2.25rem;
width: 2.25rem;
}
}
}
.row {
display: flex;
justify-content: space-between;
.left,
.right {
margin-bottom: 0.5rem;
font-size: 14px;
}
}
}

View File

@@ -0,0 +1,129 @@
<cnsl-refresh-table
[loading]="loading$ | async"
(refreshed)="refreshPage()"
[dataSize]="dataSource.data.length"
[emitRefreshOnPreviousRoutes]="[
'/instance/smtpprovider/aws-ses/create',
'/instance/smtpprovider/generic/create',
'/instance/smtpprovider/google/create',
'/instance/smtpprovider/mailgun/create',
'/instance/smtpprovider/mailjet/create',
'/instance/smtpprovider/postmark/create',
'/instance/smtpprovider/sendgrid/create',
'/instance/smtpprovider/mailchimp/create',
'/instance/smtpprovider/brevo/create'
]"
[timestamp]="configsResult?.details?.viewTimestamp"
[selection]="selection"
[hideRefresh]="true"
>
<div class="table-wrapper">
<table class="table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="activated">
<th class="availability" mat-header-cell *matHeaderCellDef>
<span>{{ 'SMTP.LIST.ACTIVATED' | translate }}</span>
</th>
<td class="pointer availability" mat-cell *matCellDef="let config">
<i
matTooltip="{{ 'SMTP.LIST.ACTIVATED' | translate }}"
*ngIf="isActive(config.state)"
class="smtp-available las la-check-circle"
data-e2e="active-provider"
></i>
</td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef>{{ 'SETTING.SMTP.DESCRIPTION' | translate }}</th>
<td class="pointer" mat-cell *matCellDef="let config">
<span>{{ config?.description }}</span>
</td>
</ng-container>
<ng-container matColumnDef="tls">
<th class="availability" mat-header-cell *matHeaderCellDef>
<span>TLS</span>
</th>
<td class="pointer availability" mat-cell *matCellDef="let config">
<i *ngIf="config.tls" class="las la-lock"></i>
<i *ngIf="!config.tls" class="las la-unlock"></i>
</td>
</ng-container>
<ng-container matColumnDef="host">
<th mat-header-cell *matHeaderCellDef>{{ 'SETTING.SMTP.HOSTANDPORT' | translate }}</th>
<td class="pointer" mat-cell *matCellDef="let config">
<span>{{ config?.host }}</span>
</td>
</ng-container>
<ng-container matColumnDef="senderAddress">
<th mat-header-cell *matHeaderCellDef>{{ 'SETTING.SMTP.SENDERADDRESS' | translate }}</th>
<td class="pointer" mat-cell *matCellDef="let config">
<span>{{ config?.senderAddress }}</span>
</td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th class="smtp-table-actions" mat-header-cell *matHeaderCellDef></th>
<td class="smtp-table-actions" mat-cell *matCellDef="let config">
<cnsl-table-actions>
<button
actions
*ngIf="!isActive(config.state)"
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-icon-button
matTooltip="{{ 'SMTP.LIST.ACTIVATE' | translate }}"
data-e2e="activate-provider-button"
(click)="activateSMTPConfig(config.id); $event.stopPropagation()"
>
<i class="las la-check-circle"></i>
</button>
<button
actions
*ngIf="isActive(config.state)"
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-icon-button
matTooltip="{{ 'SMTP.LIST.DEACTIVATE' | translate }}"
data-e2e="deactivate-provider-button"
(click)="deactivateSMTPConfig(config.id); $event.stopPropagation()"
>
<i class="las la-times-circle"></i>
</button>
<button
actions
[disabled]="(['iam.write'] | hasRole | async) === false"
mat-icon-button
color="warn"
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
data-e2e="delete-provider-button"
(click)="deleteSMTPConfig(config.id, config.senderName); $event.stopPropagation()"
>
<i class="las la-trash"></i>
</button>
</cnsl-table-actions>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" (click)="navigateToProvider(row)" mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
<div *ngIf="(loading$ | async) === false && !dataSource?.data?.length" class="no-content-row">
<i class="las la-exclamation"></i>
<span>{{ 'SMTP.LIST.EMPTY' | translate }}</span>
</div>
<cnsl-paginator
#paginator
class="paginator"
[timestamp]="configsResult?.details?.viewTimestamp"
[length]="configsResult?.details?.totalResult || 0"
[pageSize]="10"
[pageSizeOptions]="[10, 20, 50, 100]"
(page)="changePage($event)"
></cnsl-paginator>
</cnsl-refresh-table>

View File

@@ -0,0 +1,81 @@
@mixin smtp-table-theme($theme) {
$primary: map-get($theme, primary);
$warn: map-get($theme, warn);
$background: map-get($theme, background);
$accent: map-get($theme, accent);
$primary-color: map-get($primary, 500);
$warn-color: map-get($warn, 500);
$accent-color: map-get($accent, 500);
$foreground: map-get($theme, foreground);
$is-dark-theme: map-get($theme, is-dark);
$back: map-get($background, background);
.smtp-table-provider-type {
display: flex;
align-items: center;
.smtp-logo {
margin-right: 1rem;
height: 28px;
width: 28px;
flex-shrink: 0;
&.dark {
display: if($is-dark-theme, block, none);
}
&.light {
display: if($is-dark-theme, none, block);
}
}
.smtp-icon {
font-size: 1.75rem;
height: 1.75rem;
width: 1.75rem;
margin-right: 1rem;
flex-shrink: 0;
}
}
}
.smtp-margin-right {
margin-right: 0.5rem;
}
td {
outline: none;
}
tr {
outline: none;
&.disabled,
&.disabled * {
opacity: 0.8;
cursor: default;
}
}
.availability {
width: 40px;
}
.smtp-available {
color: var(--success);
}
.smtp-not-available {
color: var(--warn);
}
.smtp-table-actions {
width: 100px;
}
.la-unlock {
color: orangered;
}
.la-lock {
color: darkorange;
}

View File

@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IdpTableComponent } from './smtp-table.component';
describe('UserTableComponent', () => {
let component: IdpTableComponent;
let fixture: ComponentFixture<IdpTableComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [IdpTableComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(IdpTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,194 @@
import { SelectionModel } from '@angular/cdk/collections';
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
import { Router, RouterLink } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { SMTPConfigState } from 'src/app/proto/generated/zitadel/settings_pb';
import { ListQuery } from 'src/app/proto/generated/zitadel/object_pb';
import { LoginPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ToastService } from 'src/app/services/toast.service';
import { PageEvent, PaginatorComponent } from '../paginator/paginator.component';
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
import { ListSMTPConfigsRequest, ListSMTPConfigsResponse } from 'src/app/proto/generated/zitadel/admin_pb';
import { SMTPConfig } from 'src/app/proto/generated/zitadel/settings_pb';
import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component';
import { MatTableDataSource } from '@angular/material/table';
import { MatDialog } from '@angular/material/dialog';
@Component({
selector: 'cnsl-smtp-table',
templateUrl: './smtp-table.component.html',
styleUrls: ['./smtp-table.component.scss'],
})
export class SMTPTableComponent implements OnInit {
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
public dataSource: MatTableDataSource<SMTPConfig.AsObject> = new MatTableDataSource<SMTPConfig.AsObject>();
public selection: SelectionModel<SMTPConfig.AsObject> = new SelectionModel<SMTPConfig.AsObject>(true, []);
public configsResult?: ListSMTPConfigsResponse.AsObject;
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
public PolicyComponentServiceType: any = PolicyComponentServiceType;
public displayedColumns: string[] = ['activated', 'description', 'tls', 'host', 'senderAddress', 'actions'];
@Output() public changedSelection: EventEmitter<Array<SMTPConfig.AsObject>> = new EventEmitter();
public loginPolicy!: LoginPolicy.AsObject;
constructor(
private adminService: AdminService,
public translate: TranslateService,
private toast: ToastService,
private dialog: MatDialog,
private router: Router,
) {
this.selection.changed.subscribe(() => {
this.changedSelection.emit(this.selection.selected);
});
}
ngOnInit(): void {
this.getData(10, 0);
}
public isActive(state: number) {
return state === SMTPConfigState.SMTP_CONFIG_ACTIVE;
}
public isAllSelected(): boolean {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
return numSelected === numRows;
}
public masterToggle(): void {
this.isAllSelected() ? this.selection.clear() : this.dataSource.data.forEach((row) => this.selection.select(row));
}
public changePage(event: PageEvent): void {
this.getData(event.pageSize, event.pageIndex * event.pageSize);
}
public activateSMTPConfig(id: string): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.CONTINUE',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'SMTP.LIST.DIALOG.ACTIVATE_WARN_TITLE',
descriptionKey: 'SMTP.LIST.DIALOG.ACTIVATE_WARN_DESCRIPTION',
},
width: '400px',
});
dialogRef.afterClosed().subscribe((resp) => {
if (resp) {
this.adminService
.activateSMTPConfig(id)
.then(() => {
this.toast.showInfo('SMTP.LIST.DIALOG.ACTIVATED', true);
this.refreshPage();
})
.catch((error) => {
this.toast.showError(error);
});
}
});
}
public deactivateSMTPConfig(id: string): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.CONTINUE',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'SMTP.LIST.DIALOG.DEACTIVATE_WARN_TITLE',
descriptionKey: 'SMTP.LIST.DIALOG.DEACTIVATE_WARN_DESCRIPTION',
},
width: '400px',
});
dialogRef.afterClosed().subscribe((resp) => {
if (resp) {
this.adminService
.deactivateSMTPConfig(id)
.then(() => {
this.toast.showInfo('SMTP.LIST.DIALOG.DEACTIVATED', true);
this.refreshPage();
})
.catch((error) => {
this.toast.showError(error);
});
}
});
}
public deleteSMTPConfig(id: string, senderName: string): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'SMTP.LIST.DIALOG.DELETE_TITLE',
descriptionKey: 'SMTP.LIST.DIALOG.DELETE_DESCRIPTION',
confirmationKey: 'SMTP.LIST.DIALOG.SENDER',
confirmation: senderName,
},
width: '400px',
});
dialogRef.afterClosed().subscribe((resp) => {
if (resp) {
this.adminService
.removeSMTPConfig(id)
.then(() => {
this.toast.showInfo('SMTP.LIST.DIALOG.DELETED', true);
this.refreshPage();
})
.catch((error) => {
this.toast.showError(error);
});
}
});
}
private async getData(limit: number, offset: number): Promise<void> {
this.loadingSubject.next(true);
const req = new ListSMTPConfigsRequest();
const lq = new ListQuery();
lq.setOffset(offset);
lq.setLimit(limit);
req.setQuery(lq);
this.adminService
.listSMTPConfigs()
.then((resp) => {
this.configsResult = resp;
if (resp.resultList) {
this.dataSource.data = resp.resultList;
}
this.loadingSubject.next(false);
})
.catch((error) => {
this.toast.showError(error);
this.loadingSubject.next(false);
});
}
public refreshPage(): void {
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
}
public get createRouterLink(): RouterLink | any {
return ['/instance', 'idp', 'create'];
}
public routerLinkForRow(row: SMTPConfig.AsObject): any {
return ['/instance', 'smtpprovider', row.id];
}
public get displayedColumnsWithActions(): string[] {
return ['actions', ...this.displayedColumns];
}
public navigateToProvider(row: SMTPConfig.AsObject) {
this.router.navigate(this.routerLinkForRow(row));
}
}

View File

@@ -0,0 +1,46 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
import { TruncatePipeModule } from 'src/app/pipes/truncate-pipe/truncate-pipe.module';
import { PaginatorModule } from '../paginator/paginator.module';
import { TableActionsModule } from '../table-actions/table-actions.module';
import { SMTPTableComponent } from './smtp-table.component';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatTableModule } from '@angular/material/table';
@NgModule({
declarations: [SMTPTableComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
MatButtonModule,
TableActionsModule,
MatCheckboxModule,
MatIconModule,
MatTooltipModule,
TranslateModule,
LocalizedDatePipeModule,
TimestampToDatePipeModule,
MatTableModule,
PaginatorModule,
RouterModule,
RefreshTableModule,
HasRoleModule,
HasRolePipeModule,
TruncatePipeModule,
],
exports: [SMTPTableComponent],
})
export class SMTPTableModule {}

View File

@@ -32,6 +32,15 @@ const routes: Routes = [
serviceType: PolicyComponentServiceType.ADMIN,
},
},
{
path: 'smtpprovider',
canActivate: [AuthGuard, RoleGuard],
loadChildren: () => import('src/app/modules/smtp-provider/smtp-provider.module'),
data: {
roles: ['iam.idp.read'],
serviceType: PolicyComponentServiceType.ADMIN,
},
},
];
@NgModule({

View File

@@ -6,6 +6,8 @@ import {
ActivateLabelPolicyResponse,
ActivateSMSProviderRequest,
ActivateSMSProviderResponse,
ActivateSMTPConfigRequest,
ActivateSMTPConfigResponse,
AddAppleProviderRequest,
AddAppleProviderResponse,
AddAzureADProviderRequest,
@@ -52,6 +54,8 @@ import {
DeactivateIDPResponse,
DeactivateSMSProviderRequest,
DeactivateSMSProviderResponse,
DeactivateSMTPConfigRequest,
DeactivateSMTPConfigResponse,
DeleteProviderRequest,
DeleteProviderResponse,
GetAllowedLanguagesRequest,
@@ -135,6 +139,8 @@ import {
GetSecurityPolicyResponse,
GetSMSProviderRequest,
GetSMSProviderResponse,
GetSMTPConfigByIdRequest,
GetSMTPConfigByIdResponse,
GetSMTPConfigRequest,
GetSMTPConfigResponse,
GetSupportedLanguagesRequest,
@@ -167,6 +173,8 @@ import {
ListSecretGeneratorsResponse,
ListSMSProvidersRequest,
ListSMSProvidersResponse,
ListSMTPConfigsRequest,
ListSMTPConfigsResponse,
ListViewsRequest,
ListViewsResponse,
ReactivateIDPRequest,
@@ -193,6 +201,8 @@ import {
RemoveSecondFactorFromLoginPolicyResponse,
RemoveSMSProviderRequest,
RemoveSMSProviderResponse,
RemoveSMTPConfigRequest,
RemoveSMTPConfigResponse,
ResetCustomDomainPolicyToDefaultRequest,
ResetCustomDomainPolicyToDefaultResponse,
ResetCustomLoginTextsToDefaultRequest,
@@ -894,6 +904,17 @@ export class AdminService {
return this.grpcService.admin.getSMTPConfig(req, null).then((resp) => resp.toObject());
}
public getSMTPConfigById(id: string): Promise<GetSMTPConfigByIdResponse.AsObject> {
const req = new GetSMTPConfigByIdRequest();
req.setId(id);
return this.grpcService.admin.getSMTPConfigById(req, null).then((resp) => resp.toObject());
}
public listSMTPConfigs(): Promise<ListSMTPConfigsResponse.AsObject> {
const req = new ListSMTPConfigsRequest();
return this.grpcService.admin.listSMTPConfigs(req, null).then((resp) => resp.toObject());
}
public addSMTPConfig(req: AddSMTPConfigRequest): Promise<AddSMTPConfigResponse.AsObject> {
return this.grpcService.admin.addSMTPConfig(req, null).then((resp) => resp.toObject());
}
@@ -906,6 +927,24 @@ export class AdminService {
return this.grpcService.admin.updateSMTPConfigPassword(req, null).then((resp) => resp.toObject());
}
public activateSMTPConfig(id: string): Promise<ActivateSMTPConfigResponse.AsObject> {
const req = new ActivateSMTPConfigRequest();
req.setId(id);
return this.grpcService.admin.activateSMTPConfig(req, null).then((resp) => resp.toObject());
}
public deactivateSMTPConfig(id: string): Promise<DeactivateSMTPConfigResponse.AsObject> {
const req = new DeactivateSMTPConfigRequest();
req.setId(id);
return this.grpcService.admin.deactivateSMTPConfig(req, null).then((resp) => resp.toObject());
}
public removeSMTPConfig(id: string): Promise<RemoveSMTPConfigResponse.AsObject> {
const req = new RemoveSMTPConfigRequest();
req.setId(id);
return this.grpcService.admin.removeSMTPConfig(req, null).then((resp) => resp.toObject());
}
/* sms */
public listSMSProviders(): Promise<ListSMSProvidersResponse.AsObject> {

View File

@@ -1374,6 +1374,8 @@
}
},
"SMTP": {
"TITLE": "SMTP настройки",
"DESCRIPTION": "Описание",
"SENDERADDRESS": "Имейл адрес на изпращача",
"SENDERNAME": "Име на изпращача",
"REPLYTOADDRESS": "Reply-to адрес",
@@ -1384,6 +1386,7 @@
"PASSWORDSET": "Паролата за SMTP бе зададена успешно.",
"TLS": "Сигурност на транспортния слой (TLS)",
"SAVED": "Запазено успешно!",
"NOCHANGES": "Без промени!",
"REQUIREDWARN": "За да изпращате известия от вашия домейн, трябва да въведете своите SMTP данни."
},
"SMS": {
@@ -2208,6 +2211,48 @@
"1": "Позволен"
}
},
"SMTP": {
"LIST": {
"TITLE": "SMTP доставчик",
"DESCRIPTION": "Това са SMTP доставчиците за вашето копие на Zitadel. Активирайте този, който искате да използвате, за да изпращате известия до вашите потребители.",
"EMPTY": "Няма наличен SMTP доставчик",
"ACTIVATED": "Активиран",
"ACTIVATE": "Активирайте доставчика",
"DEACTIVATE": "Деактивирайте доставчика",
"TYPE": "Тип",
"DIALOG": {
"ACTIVATED": "SMTP конфигурацията е активирана",
"ACTIVATE_WARN_TITLE": "Активирайте SMTP конфигурацията",
"ACTIVATE_WARN_DESCRIPTION": "На път сте да активирате SMTP конфигурация. Първо ще деактивираме текущия активен доставчик и след това ще активираме тази конфигурация. Сигурен ли си?",
"DEACTIVATE_WARN_TITLE": "Деактивирайте SMTP конфигурацията",
"DEACTIVATE_WARN_DESCRIPTION": "На път сте да деактивирате SMTP конфигурация. Сигурен ли си?",
"DEACTIVATED": "SMTP конфигурацията е деактивирана",
"DELETE_TITLE": "Изтриване на SMTP конфигурация",
"DELETE_DESCRIPTION": "На път сте да изтриете конфигурация. Потвърдете това действие, като въведете името на подателя",
"DELETED": "SMTP конфигурацията е изтрита",
"SENDER": "Въведете {{ value }}, за да изтриете тази SMTP конфигурация."
}
},
"CREATE": {
"TITLE": "Добавете SMTP доставчик",
"DESCRIPTION": "Изберете един или повече от следните доставчици.",
"STEPS": {
"TITLE": "Добавете {{ value }} SMTP доставчик",
"CREATE_DESC_TITLE": "Въведете своите {{ value }} SMTP настройки стъпка по стъпка",
"CURRENT_DESC_TITLE": "Това са вашите SMTP настройки",
"PROVIDER_SETTINGS": "Настройки на SMTP доставчик",
"SENDER_SETTINGS": "Настройки на изпращача",
"TEST_SETTINGS": "Тествайте настройките на SMTP"
}
},
"DETAIL": {
"TITLE": "Настройки на SMTP доставчик"
},
"EMPTY": "Няма наличен SMTP доставчик",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Приложения",
"COMPLIANCE": "Съответствие с OIDC",

View File

@@ -1381,6 +1381,8 @@
}
},
"SMTP": {
"TITLE": "Nastavení SMTP",
"DESCRIPTION": "Popis",
"SENDERADDRESS": "E-mailová adresa odesílatele",
"SENDERNAME": "Jméno odesílatele",
"REPLYTOADDRESS": "Adresa pro odpovědi",
@@ -1391,6 +1393,7 @@
"PASSWORDSET": "SMTP heslo bylo úspěšně nastaveno.",
"TLS": "Zabezpečení transportní vrstvy (TLS)",
"SAVED": "Úspěšně uloženo!",
"NOCHANGES": "Žádné změny!",
"REQUIREDWARN": "Pro odesílání oznámení z vaší domény musíte zadat vaše SMTP údaje."
},
"SMS": {
@@ -2227,6 +2230,48 @@
"1": "Povoleno"
}
},
"SMTP": {
"LIST": {
"TITLE": "Poskytovatel SMTP",
"DESCRIPTION": "Toto jsou poskytovatelé SMTP pro vaši instanci Zitadel. Aktivujte ten, který chcete používat k odesílání upozornění svým uživatelům.",
"EMPTY": "Není k dispozici žádný poskytovatel SMTP",
"ACTIVATED": "Aktivováno",
"ACTIVATE": "Aktivujte poskytovatele",
"DEACTIVATE": "Deaktivovat poskytovatele",
"TYPE": "Typ",
"DIALOG": {
"ACTIVATED": "Konfigurace SMTP byla aktivována",
"ACTIVATE_WARN_TITLE": "Aktivujte konfiguraci SMTP",
"ACTIVATE_WARN_DESCRIPTION": "Chystáte se aktivovat konfiguraci SMTP. Nejprve deaktivujeme aktuálního aktivního poskytovatele a poté aktivujeme tuto konfiguraci. Jsi si jistá?",
"DEACTIVATE_WARN_TITLE": "Deaktivujte konfiguraci SMTP",
"DEACTIVATE_WARN_DESCRIPTION": "Chystáte se deaktivovat konfiguraci SMTP. Jsi si jistá?",
"DEACTIVATED": "Konfigurace SMTP byla deaktivována",
"DELETE_TITLE": "Smazat konfiguraci SMTP",
"DELETE_DESCRIPTION": "Chystáte se smazat konfiguraci. Potvrďte tuto akci zadáním jména odesílatele",
"DELETED": "Konfigurace SMTP byla smazána",
"SENDER": "Chcete-li smazat tuto konfiguraci SMTP, zadejte {{ value }}."
}
},
"CREATE": {
"TITLE": "Přidat poskytovatele SMTP",
"DESCRIPTION": "Vyberte jednoho nebo více z následujících poskytovatelů.",
"STEPS": {
"TITLE": "Přidejte {{ value }} poskytovatele SMTP",
"CREATE_DESC_TITLE": "Krok za krokem zadejte nastavení SMTP {{ value }}",
"CURRENT_DESC_TITLE": "Toto jsou vaše nastavení SMTP",
"PROVIDER_SETTINGS": "Nastavení poskytovatele SMTP",
"SENDER_SETTINGS": "Nastavení odesílatele",
"TEST_SETTINGS": "Otestujte nastavení SMTP"
}
},
"DETAIL": {
"TITLE": "Nastavení poskytovatele SMTP"
},
"EMPTY": "Není k dispozici žádný poskytovatel SMTP",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Aplikace",
"COMPLIANCE": "OIDC Kompatibilita",

View File

@@ -1380,6 +1380,8 @@
}
},
"SMTP": {
"TITLE": "SMTP Einstellungen",
"DESCRIPTION": "Beschreibung",
"SENDERADDRESS": "Sender Email-Adresse",
"SENDERNAME": "Sender Name",
"REPLYTOADDRESS": "Reply-to-Adresse",
@@ -1390,6 +1392,7 @@
"PASSWORDSET": "SMTP Passwort erfolgreich gesetzt.",
"TLS": "Transport Layer Security (TLS)",
"SAVED": "Erfolgreich gespeichert.",
"NOCHANGES": "Keine Änderungen!",
"REQUIREDWARN": "Damit Mails von Ihrer Domain verschickt werden können, müssen Sie Ihre SMTP Einstellungen konfigurieren."
},
"SMS": {
@@ -2217,6 +2220,48 @@
"1": "Erlaubt"
}
},
"SMTP": {
"LIST": {
"TITLE": "SMTP-Anbieter",
"DESCRIPTION": "Dies sind die SMTP-Anbieter für Ihre Zitadel-Instanz. Aktivieren Sie diejenige, die Sie zum Senden von Benachrichtigungen an Ihre Benutzer verwenden möchten.",
"EMPTY": "Kein SMTP-Anbieter verfügbar",
"ACTIVATED": "Aktiviert",
"ACTIVATE": "Anbieter aktivieren",
"DEACTIVATE": "Anbieter deaktivieren",
"TYPE": "Typ",
"DIALOG": {
"ACTIVATED": "Die SMTP-Konfiguration wurde aktiviert",
"ACTIVATE_WARN_TITLE": "Aktivieren Sie die SMTP-Konfiguration",
"ACTIVATE_WARN_DESCRIPTION": "Sie sind dabei, eine SMTP-Konfiguration zu aktivieren. Zuerst deaktivieren wir den aktuell aktiven Anbieter und aktivieren dann diese Konfiguration. Bist du sicher?",
"DEACTIVATE_WARN_TITLE": "Deaktivieren Sie die SMTP-Konfiguration",
"DEACTIVATE_WARN_DESCRIPTION": "Sie sind dabei, eine SMTP-Konfiguration zu deaktivieren. Bist du sicher?",
"DEACTIVATED": "Die SMTP-Konfiguration wurde deaktiviert",
"DELETE_TITLE": "SMTP-Konfiguration löschen",
"DELETE_DESCRIPTION": "Sie sind dabei, eine Konfiguration zu löschen. Bestätigen Sie diese Aktion, indem Sie den Absendernamen eingeben",
"DELETED": "SMTP-Konfiguration wurde gelöscht",
"SENDER": "Geben Sie {{ value }} ein, um diese SMTP-Konfiguration zu löschen."
}
},
"CREATE": {
"TITLE": "SMTP-Anbieter hinzufügen",
"DESCRIPTION": "Wählen Sie einen oder mehrere der folgenden Anbieter aus.",
"STEPS": {
"TITLE": "Fügen Sie {{ value }} SMTP-Anbieter hinzu",
"CREATE_DESC_TITLE": "Geben Sie Schritt für Schritt Ihre {{ value }} SMTP-Einstellungen ein",
"CURRENT_DESC_TITLE": "Dies sind Ihre SMTP-Einstellungen",
"PROVIDER_SETTINGS": "SMTP-Anbietereinstellungen",
"SENDER_SETTINGS": "Absendereinstellungen",
"TEST_SETTINGS": "Testen Sie die SMTP-Einstellungen"
}
},
"DETAIL": {
"TITLE": "SMTP-Anbietereinstellungen"
},
"EMPTY": "Kein SMTP-Anbieter verfügbar",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Apps",
"COMPLIANCE": "OIDC Einhaltung",

View File

@@ -1381,6 +1381,8 @@
}
},
"SMTP": {
"TITLE": "SMTP Provider",
"DESCRIPTION": "Description",
"SENDERADDRESS": "Sender Email Address",
"SENDERNAME": "Sender Name",
"REPLYTOADDRESS": "Reply-to Address",
@@ -1391,6 +1393,7 @@
"PASSWORDSET": "SMTP Password was set successfully.",
"TLS": "Transport Layer Security (TLS)",
"SAVED": "Saved successfully!",
"NOCHANGES": "No changes!",
"REQUIREDWARN": "To send notifications from your domain, you have to enter your SMTP data."
},
"SMS": {
@@ -2236,6 +2239,48 @@
"1": "Allowed"
}
},
"SMTP": {
"LIST": {
"TITLE": "SMTP Provider",
"DESCRIPTION": "These are the SMTP providers for your Zitadel instance. Activate the one you want to use to send notifications to your users.",
"EMPTY": "No SMTP Provider available",
"ACTIVATED": "Activated",
"ACTIVATE": "Activate provider",
"DEACTIVATE": "Deactivate provider",
"TYPE": "Type",
"DIALOG": {
"ACTIVATED": "SMTP config has been activated",
"ACTIVATE_WARN_TITLE": "Activate SMTP config",
"ACTIVATE_WARN_DESCRIPTION": "You are about to activate an SMTP configuration. First we'll deactivate the current active provider and then activate this configuration. Are you sure?",
"DEACTIVATE_WARN_TITLE": "Deactivate SMTP config",
"DEACTIVATE_WARN_DESCRIPTION": "You are about to deactivate an SMTP configuration. Are you sure?",
"DEACTIVATED": "SMTP config has been deactivated",
"DELETE_TITLE": "Delete SMTP config",
"DELETE_DESCRIPTION": "You are about to delete a configuration. Confirm this action typing the sender name",
"DELETED": "SMTP config has been deleted",
"SENDER": "Type {{value}}, to delete this SMTP configuration."
}
},
"CREATE": {
"TITLE": "Add SMTP provider",
"DESCRIPTION": "Select one ore more of the following providers.",
"STEPS": {
"TITLE": "Add {{ value }} SMTP Provider",
"CREATE_DESC_TITLE": "Enter your {{ value }} SMTP settings step by step",
"CURRENT_DESC_TITLE": "These are your SMTP settings",
"PROVIDER_SETTINGS": "SMTP Provider Settings",
"SENDER_SETTINGS": "Sender Settings",
"TEST_SETTINGS": "Test SMTP Settings"
}
},
"DETAIL": {
"TITLE": "SMTP Provider Settings"
},
"EMPTY": "No SMTP provider available",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Applications",
"COMPLIANCE": "OIDC Compliance",

View File

@@ -1382,6 +1382,8 @@
}
},
"SMTP": {
"TITLE": "Ajustes SMTP",
"DESCRIPTION": "Descripción",
"SENDERADDRESS": "Dirección email del emisor",
"SENDERNAME": "Nombre del emisor",
"REPLYTOADDRESS": "Dirección Reply-To",
@@ -1392,6 +1394,7 @@
"PASSWORDSET": "La contraseña SMTP se estableció con éxito.",
"TLS": "Transport Layer Security (TLS)",
"SAVED": "¡Se guardó con éxito!",
"NOCHANGES": "¡Sin cambios!",
"REQUIREDWARN": "Para enviar notificaciones para tu dominio, debes introducir tus datos SMTP."
},
"SMS": {
@@ -2215,6 +2218,48 @@
"1": "Permitido"
}
},
"SMTP": {
"LIST": {
"TITLE": "Proveedor SMTP",
"DESCRIPTION": "Estos son los proveedores SMTP para tu instancia de Zitadel. Activa el que quieras utilizar para enviar notificaciones a tus usuarios.",
"EMPTY": "No hay ningún proveedor SMTP disponible",
"ACTIVATED": "Activado",
"ACTIVATE": "Activar proveedor",
"DEACTIVATE": "Desactivar proveedor",
"TYPE": "Tipo",
"DIALOG": {
"ACTIVATED": "Tu configuración SMTP ha sido activada",
"ACTIVATE_WARN_TITLE": "Activar configuración SMTP",
"ACTIVATE_WARN_DESCRIPTION": "Estás a punto de activar una configuración SMTP. Primero desactivaremos la configuración de tu proveedor actual y después activaremos esta configuración. ¿Estás seguro?",
"DEACTIVATE_WARN_TITLE": "Desactivar configuración SMTP",
"DEACTIVATE_WARN_DESCRIPTION": "Estás a punto de desactivar una configuración SMTP. ¿Está seguro?",
"DEACTIVATED": "La configuración SMTP ha sido desactivada",
"DELETE_TITLE": "Eliminar configuración SMTP",
"DELETE_DESCRIPTION": "Estás a punto de eliminar una configuración. Confirma esta acción escribiendo el nombre del remitente",
"DELETED": "La configuración SMTP ha sido eliminada",
"SENDER": "Escribe {{ value }} para eliminar esta configuración SMTP."
}
},
"CREATE": {
"TITLE": "Agrega un proveedor SMTP",
"DESCRIPTION": "Selecciona uno o más de los siguientes proveedores.",
"STEPS": {
"TITLE": "Agrega un proveedor SMTP {{ value }} ",
"CREATE_DESC_TITLE": "Introduce tu configuración SMTP de {{ value }} paso a paso",
"CURRENT_DESC_TITLE": "Estas son tus configuraciones SMTP",
"PROVIDER_SETTINGS": "Configuración del proveedor SMTP",
"SENDER_SETTINGS": "Configuración del remitente",
"TEST_SETTINGS": "Probar la configuración SMTP"
}
},
"DETAIL": {
"TITLE": "Configuración del proveedor SMTP"
},
"EMPTY": "No hay ningún proveedor SMTP disponible",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Aplicaciones",
"COMPLIANCE": "Cumplimiento OIDC",

View File

@@ -1380,6 +1380,8 @@
}
},
"SMTP": {
"TITLE": "Paramètres SMTP",
"DESCRIPTION": "Description",
"SENDERADDRESS": "Adresse e-mail de l'expéditeur",
"SENDERNAME": "Nom de l'expéditeur",
"REPLYTOADDRESS": "Adresse Reply-to",
@@ -1390,6 +1392,7 @@
"PASSWORDSET": "Le mot de passe SMTP a été défini avec succès.",
"TLS": "Sécurité de la couche de transport (TLS)",
"SAVED": "Enregistré avec succès!",
"NOCHANGES": "Aucun changement!",
"REQUIREDWARN": "Pour envoyer des notifications depuis votre domaine, vous devez entrer vos données SMTP."
},
"SMS": {
@@ -2218,6 +2221,48 @@
"1": "Autorisée"
}
},
"SMTP": {
"LIST": {
"TITLE": "Fournisseur SMTP",
"DESCRIPTION": "Ce sont les fournisseurs SMTP de votre instance Zitadel. Activez celui que vous souhaitez utiliser pour envoyer des notifications à vos utilisateurs.",
"EMPTY": "Aucun fournisseur SMTP disponible",
"ACTIVATED": "Activé",
"ACTIVATE": "Activer le fournisseur",
"DEACTIVATE": "Désactiver le fournisseur",
"TYPE": "Taper",
"DIALOG": {
"ACTIVATED": "La configuration SMTP a été activée",
"ACTIVATE_WARN_TITLE": "Activer la configuration SMTP",
"ACTIVATE_WARN_DESCRIPTION": "Vous êtes sur le point d'activer une configuration SMTP. Nous allons dabord désactiver le fournisseur actif actuel, puis activer cette configuration. Es-tu sûr?",
"DEACTIVATE_WARN_TITLE": "Désactiver la configuration SMTP",
"DEACTIVATE_WARN_DESCRIPTION": "Vous êtes sur le point de désactiver une configuration SMTP. Es-tu sûr?",
"DEACTIVATED": "La configuration SMTP a été désactivée",
"DELETE_TITLE": "Supprimer la configuration SMTP",
"DELETE_DESCRIPTION": "Vous êtes sur le point de supprimer une configuration. Confirmez cette action en tapant le nom de l'expéditeur",
"DELETED": "La configuration SMTP a été supprimée",
"SENDER": "Tapez {{ value }} pour supprimer cette configuration SMTP."
}
},
"CREATE": {
"TITLE": "Ajouter un fournisseur SMTP",
"DESCRIPTION": "Sélectionnez un ou plusieurs des fournisseurs suivants.",
"STEPS": {
"TITLE": "Ajouter {{ value }} fournisseur SMTP",
"CREATE_DESC_TITLE": "Entrez vos paramètres SMTP {{ value }} étape par étape",
"CURRENT_DESC_TITLE": "Ce sont vos paramètres SMTP",
"PROVIDER_SETTINGS": "Paramètres du fournisseur SMTP",
"SENDER_SETTINGS": "Paramètres de l'expéditeur",
"TEST_SETTINGS": "Tester les paramètres SMTP"
}
},
"DETAIL": {
"TITLE": "Paramètres du fournisseur SMTP"
},
"EMPTY": "Aucun fournisseur SMTP disponible",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Applications",
"COMPLIANCE": "Conformité à l'OIDC",

View File

@@ -1380,6 +1380,8 @@
}
},
"SMTP": {
"TITLE": "Impostazioni SMTP",
"DESCRIPTION": "Descrizione",
"SENDERADDRESS": "Indirizzo email del mittente",
"SENDERNAME": "Nome del mittente",
"REPLYTOADDRESS": "Indirizzo Reply-to",
@@ -1390,6 +1392,7 @@
"PASSWORDSET": "SMTP Password impostata con successo.",
"TLS": "Transport Layer Security (TLS)",
"SAVED": "Salvato con successo!",
"NOCHANGES": "Nessun cambiamento!",
"REQUIREDWARN": "Per inviare notifiche dal tuo dominio, devi inserire i tuoi dati SMTP."
},
"SMS": {
@@ -2218,6 +2221,48 @@
"1": "Consentito"
}
},
"SMTP": {
"LIST": {
"TITLE": "Fornitore SMTP",
"DESCRIPTION": "Questi sono i provider SMTP per la tua istanza Zitadel. Attiva quello che desideri utilizzare per inviare notifiche ai tuoi utenti.",
"EMPTY": "Nessun provider SMTP disponibile",
"ACTIVATED": "Attivato",
"ACTIVATE": "Attiva fornitore",
"DEACTIVATE": "Disattiva fornitore",
"TYPE": "Tipo",
"DIALOG": {
"ACTIVATED": "La configurazione SMTP è stata attivata",
"ACTIVATE_WARN_TITLE": "Attiva la configurazione SMTP",
"ACTIVATE_WARN_DESCRIPTION": "Stai per attivare una configurazione SMTP. Per prima cosa disattiveremo il provider attualmente attivo e poi attiveremo questa configurazione. Sei sicuro?",
"DEACTIVATE_WARN_TITLE": "Disattiva la configurazione SMTP",
"DEACTIVATE_WARN_DESCRIPTION": "Stai per disattivare una configurazione SMTP. Sei sicuro?",
"DEACTIVATED": "La configurazione SMTP è stata disattivata",
"DELETE_TITLE": "Elimina configurazione SMTP",
"DELETE_DESCRIPTION": "Stai per eliminare una configurazione. Conferma questa azione digitando il nome del mittente",
"DELETED": "La configurazione SMTP è stata eliminata",
"SENDER": "Digita {{ value }} per eliminare questa configurazione SMTP."
}
},
"CREATE": {
"TITLE": "Aggiungi provider SMTP",
"DESCRIPTION": "Seleziona uno o più dei seguenti fornitori.",
"STEPS": {
"TITLE": "Aggiungi {{ value }} provider SMTP",
"CREATE_DESC_TITLE": "Inserisci le tue impostazioni SMTP {{ value }} passo dopo passo",
"CURRENT_DESC_TITLE": "Queste sono le tue impostazioni SMTP",
"PROVIDER_SETTINGS": "Impostazioni del provider SMTP",
"SENDER_SETTINGS": "Impostazioni mittente",
"TEST_SETTINGS": "Testare le impostazioni SMTP"
}
},
"DETAIL": {
"TITLE": "Impostazioni del provider SMTP"
},
"EMPTY": "Nessun provider SMTP disponibile",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Applicazioni",
"COMPLIANCE": "Conformità con OIDC",

View File

@@ -1381,6 +1381,8 @@
}
},
"SMTP": {
"TITLE": "SMTP設定",
"DESCRIPTION": "説明",
"SENDERADDRESS": "送信者のメールアドレス",
"SENDERNAME": "送信者名",
"REPLYTOADDRESS": "返信先アドレス",
@@ -1391,6 +1393,7 @@
"PASSWORDSET": "SMTPパスワードは正常に設定されました。",
"TLS": "Transport Layer Security (TLS)",
"SAVED": "正常に保存されました!",
"NOCHANGES": "変更はありません!",
"REQUIREDWARN": "ドメインから通知を送信するには、SMTP情報を入力する必要があります。"
},
"SMS": {
@@ -2209,6 +2212,48 @@
"1": "有効"
}
},
"SMTP": {
"LIST": {
"TITLE": "SMTPプロバイダー",
"DESCRIPTION": "これらは、Zitadel インスタンスの SMTP プロバイダーです。ユーザーに通知を送信するために使用するものをアクティブにします。",
"EMPTY": "使用可能な SMTP プロバイダーがありません",
"ACTIVATED": "アクティブ化された",
"ACTIVATE": "プロバイダーをアクティブ化する",
"DEACTIVATE": "プロバイダーを非アクティブ化する",
"TYPE": "タイプ",
"DIALOG": {
"ACTIVATED": "SMTP設定が有効化されました",
"ACTIVATE_WARN_TITLE": "SMTP設定を有効にする",
"ACTIVATE_WARN_DESCRIPTION": "SMTP 構成をアクティブにしようとしています。まず、現在アクティブなプロバイダーを非アクティブ化してから、この構成をアクティブ化します。本気ですか?",
"DEACTIVATE_WARN_TITLE": "SMTP設定を無効にする",
"DEACTIVATE_WARN_DESCRIPTION": "SMTP 構成を非アクティブ化しようとしています。本気ですか?",
"DEACTIVATED": "SMTP設定が無効化されました",
"DELETE_TITLE": "SMTP設定を削除する",
"DELETE_DESCRIPTION": "構成を削除しようとしています。送信者名を入力してこのアクションを確認します",
"DELETED": "SMTP設定が削除されました",
"SENDER": "この SMTP 構成を削除するには、「{{ value }}」と入力します。"
}
},
"CREATE": {
"TITLE": "SMTPプロバイダーの追加",
"DESCRIPTION": "次のプロバイダーから 1 つ以上を選択します。",
"STEPS": {
"TITLE": "{{ value }} SMTP プロバイダーを追加",
"CREATE_DESC_TITLE": "{{ value }} SMTP 設定をステップごとに入力します",
"CURRENT_DESC_TITLE": "これらは SMTP 設定です",
"PROVIDER_SETTINGS": "SMTPプロバイダーの設定",
"SENDER_SETTINGS": "送信者の設定",
"TEST_SETTINGS": "SMTP設定をテストする"
}
},
"DETAIL": {
"TITLE": "SMTPプロバイダーの設定"
},
"EMPTY": "使用可能な SMTP プロバイダーがありません",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "アプリケーション",
"COMPLIANCE": "OIDCコンプライアンス",

View File

@@ -1382,6 +1382,8 @@
}
},
"SMTP": {
"TITLE": "SMTP подесувања",
"DESCRIPTION": "Опис",
"SENDERADDRESS": "Адреса на испраќачот",
"SENDERNAME": "Име на испраќачот",
"REPLYTOADDRESS": "Reply-to адреса",
@@ -1392,6 +1394,7 @@
"PASSWORDSET": "SMTP лозинката е успешно поставена.",
"TLS": "Transport Layer Security (TLS)",
"SAVED": "Успешно зачувано!",
"NOCHANGES": "Нема промени!",
"REQUIREDWARN": "За да испраќате известувања од вашиот домен, мора да ги внесете вашите SMTP податоци."
},
"SMS": {
@@ -2215,6 +2218,48 @@
"1": "Дозволено"
}
},
"SMTP": {
"LIST": {
"TITLE": "SMTP провајдер",
"DESCRIPTION": "Ова се давателите на SMTP за вашиот пример Zitadel. Активирајте го оној што сакате да го користите за испраќање известувања до вашите корисници.",
"EMPTY": "Нема достапен SMTP провајдер",
"ACTIVATED": "Активиран",
"ACTIVATE": "Активирајте го провајдерот",
"DEACTIVATE": "Деактивирајте го провајдерот",
"TYPE": "Тип",
"DIALOG": {
"ACTIVATED": "SMTP конфигурацијата е активирана",
"ACTIVATE_WARN_TITLE": "Активирајте SMTP конфигурација",
"ACTIVATE_WARN_DESCRIPTION": "Ќе активирате SMTP конфигурација. Прво ќе го деактивираме тековниот активен провајдер, а потоа ќе ја активираме оваа конфигурација. Дали си сигурен?",
"DEACTIVATE_WARN_TITLE": "Деактивирајте ја конфигурацијата SMTP",
"DEACTIVATE_WARN_DESCRIPTION": "Ќе деактивирате SMTP конфигурација. Дали си сигурен?",
"DEACTIVATED": "SMTP конфигурацијата е деактивирана",
"DELETE_TITLE": "Избришете ја конфигурацијата SMTP",
"DELETE_DESCRIPTION": "Ќе избришете конфигурација. Потврдете го ова дејство со внесување на името на испраќачот",
"DELETED": "SMTP конфигурацијата е избришана",
"SENDER": "Внесете {{ value }}, за да ја избришете оваа SMTP конфигурација."
}
},
"CREATE": {
"TITLE": "Додадете SMTP провајдер",
"DESCRIPTION": "Изберете еден или повеќе од следните провајдери.",
"STEPS": {
"TITLE": "Додадете {{ value }} SMTP провајдер",
"CREATE_DESC_TITLE": "Внесете ги вашите поставки за {{ value }} SMTP чекор по чекор",
"CURRENT_DESC_TITLE": "Ова се вашите поставки за SMTP",
"PROVIDER_SETTINGS": "Поставки на провајдерот SMTP",
"SENDER_SETTINGS": "Поставки на испраќачот",
"TEST_SETTINGS": "Тестирајте ги поставките за SMTP"
}
},
"DETAIL": {
"TITLE": "Поставки на провајдерот SMTP"
},
"EMPTY": "Нема достапен SMTP провајдер",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Апликации",
"COMPLIANCE": "OIDC Соодветност",

View File

@@ -1381,6 +1381,8 @@
}
},
"SMTP": {
"TITLE": "SMTP Instellingen",
"DESCRIPTION": "Beschrijving",
"SENDERADDRESS": "Afzender Email Adres",
"SENDERNAME": "Afzender Naam",
"REPLYTOADDRESS": "Antwoord-naar Adres",
@@ -1391,6 +1393,7 @@
"PASSWORDSET": "SMTP Wachtwoord is succesvol ingesteld.",
"TLS": "Transport Layer Security (TLS)",
"SAVED": "Succesvol opgeslagen!",
"NOCHANGES": "Geen veranderingen!",
"REQUIREDWARN": "Om notificaties te kunnen versturen vanaf uw domein, moet u uw SMTP-gegevens invoeren."
},
"SMS": {
@@ -2236,6 +2239,48 @@
"1": "Toegestaan"
}
},
"SMTP": {
"LIST": {
"TITLE": "SMTP-provider",
"DESCRIPTION": "Dit zijn de SMTP-providers voor uw Zitadel-instantie. Activeer degene die u wilt gebruiken om meldingen naar uw gebruikers te sturen.",
"EMPTY": "Geen SMTP-provider beschikbaar",
"ACTIVATED": "Geactiveerd",
"ACTIVATE": "Aanbieder activeren",
"DEACTIVATE": "Aanbieder deactiveren",
"TYPE": "Type",
"DIALOG": {
"ACTIVATED": "SMTP-configuratie is geactiveerd",
"ACTIVATE_WARN_TITLE": "Activeer SMTP-configuratie",
"ACTIVATE_WARN_DESCRIPTION": "U staat op het punt een SMTP-configuratie te activeren. Eerst deactiveren we de huidige actieve provider en activeren vervolgens deze configuratie. Weet je het zeker?",
"DEACTIVATE_WARN_TITLE": "Deactiveer SMTP-configuratie",
"DEACTIVATE_WARN_DESCRIPTION": "U staat op het punt een SMTP-configuratie te deactiveren. Weet je het zeker?",
"DEACTIVATED": "SMTP-configuratie is gedeactiveerd",
"DELETE_TITLE": "SMTP-configuratie verwijderen",
"DELETE_DESCRIPTION": "U staat op het punt een configuratie te verwijderen. Bevestig deze actie door de naam van de afzender te typen",
"DELETED": "SMTP-configuratie is verwijderd",
"SENDER": "Typ {{ value }} om deze SMTP-configuratie te verwijderen."
}
},
"CREATE": {
"TITLE": "SMTP-provider toevoegen",
"DESCRIPTION": "Selecteer één of meer van de volgende aanbieders.",
"STEPS": {
"TITLE": "Voeg {{ value }} SMTP-provider toe",
"CREATE_DESC_TITLE": "Voer stap voor stap uw {{ value }} SMTP-instellingen in",
"CURRENT_DESC_TITLE": "Dit zijn uw SMTP-instellingen",
"PROVIDER_SETTINGS": "SMTP-providerinstellingen",
"SENDER_SETTINGS": "Afzenderinstellingen",
"TEST_SETTINGS": "SMTP-instellingen testen"
}
},
"DETAIL": {
"TITLE": "SMTP-providerinstellingen"
},
"EMPTY": "Geen SMTP-provider beschikbaar",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Toepassingen",
"COMPLIANCE": "OIDC Conformiteit",

View File

@@ -1380,6 +1380,8 @@
}
},
"SMTP": {
"TITLE": "Ustawienia SMTP",
"DESCRIPTION": "Opis",
"SENDERADDRESS": "Adres e-mail nadawcy",
"SENDERNAME": "Nazwa nadawcy",
"REPLYTOADDRESS": "Adres Reply-to",
@@ -1390,6 +1392,7 @@
"PASSWORDSET": "Hasło SMTP zostało pomyślnie ustawione.",
"TLS": "Bezpieczeństwo warstwy transportu (TLS)",
"SAVED": "Pomyślnie zapisano!",
"NOCHANGES": "Bez zmian!",
"REQUIREDWARN": "Aby wysyłać powiadomienia z twojej domeny, musisz podać dane SMTP."
},
"SMS": {
@@ -2218,6 +2221,48 @@
"1": "Dozwolone"
}
},
"SMTP": {
"LIST": {
"TITLE": "Dostawca SMTP",
"DESCRIPTION": "To są dostawcy SMTP dla Twojej instancji Zitadel. Aktywuj ten, którego chcesz używać do wysyłania powiadomień do użytkowników.",
"EMPTY": "Brak dostępnego dostawcy SMTP",
"ACTIVATED": "Aktywowany",
"ACTIVATE": "Aktywuj dostawcę",
"DEACTIVATE": "Dezaktywuj dostawcę",
"TYPE": "Typ",
"DIALOG": {
"ACTIVATED": "Konfiguracja SMTP została aktywowana",
"ACTIVATE_WARN_TITLE": "Aktywuj konfigurację SMTP",
"ACTIVATE_WARN_DESCRIPTION": "Zamierzasz aktywować konfigurację SMTP. Najpierw dezaktywujemy bieżącego aktywnego dostawcę, a następnie aktywujemy tę konfigurację. Jesteś pewny?",
"DEACTIVATE_WARN_TITLE": "Dezaktywuj konfigurację SMTP",
"DEACTIVATE_WARN_DESCRIPTION": "Zamierzasz dezaktywować konfigurację SMTP. Jesteś pewny?",
"DEACTIVATED": "Konfiguracja SMTP została dezaktywowana",
"DELETE_TITLE": "Usuń konfigurację SMTP",
"DELETE_DESCRIPTION": "Zamierzasz usunąć konfigurację. Potwierdź tę czynność, wpisując nazwę nadawcy",
"DELETED": "Konfiguracja SMTP została usunięta",
"SENDER": "Wpisz {{ value }}, aby usunąć tę konfigurację SMTP."
}
},
"CREATE": {
"TITLE": "Dodaj dostawcę SMTP",
"DESCRIPTION": "Wybierz jednego lub więcej z poniższych dostawców.",
"STEPS": {
"TITLE": "Dodaj {{ value }} dostawcę SMTP",
"CREATE_DESC_TITLE": "Wprowadź krok po kroku ustawienia SMTP {{ value }}",
"CURRENT_DESC_TITLE": "To są Twoje ustawienia SMTP",
"PROVIDER_SETTINGS": "Ustawienia dostawcy SMTP",
"SENDER_SETTINGS": "Ustawienia nadawcy",
"TEST_SETTINGS": "Przetestuj ustawienia SMTP"
}
},
"DETAIL": {
"TITLE": "Ustawienia dostawcy SMTP"
},
"EMPTY": "Brak dostępnego dostawcy SMTP",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Aplikacje",
"COMPLIANCE": "Zgodność OIDC",

View File

@@ -1382,6 +1382,8 @@
}
},
"SMTP": {
"TITLE": "Configurações SMTP",
"DESCRIPTION": "Descrição",
"SENDERADDRESS": "Endereço de e-mail do remetente",
"SENDERNAME": "Nome do remetente",
"REPLYTOADDRESS": "Endereço Reply-To",
@@ -1392,6 +1394,7 @@
"PASSWORDSET": "Senha do SMTP definida com sucesso.",
"TLS": "Transport Layer Security (TLS)",
"SAVED": "Salvo com sucesso!",
"NOCHANGES": "Sem alterações!",
"REQUIREDWARN": "Para enviar notificações do seu domínio, você precisa inserir seus dados SMTP."
},
"SMS": {
@@ -2213,6 +2216,48 @@
"1": "Permitido"
}
},
"SMTP": {
"LIST": {
"TITLE": "Provedor SMTP",
"DESCRIPTION": "Estes são os provedores SMTP para sua instância Zitadel. Ative aquele que deseja usar para enviar notificações aos seus usuários.",
"EMPTY": "Nenhum provedor SMTP disponível",
"ACTIVATED": "Ativado",
"ACTIVATE": "Ativar provedor",
"DEACTIVATE": "Desativar provedor",
"TYPE": "Tipo",
"DIALOG": {
"ACTIVATED": "A configuração SMTP foi ativada",
"ACTIVATE_WARN_TITLE": "Ativar configuração SMTP",
"ACTIVATE_WARN_DESCRIPTION": "Você está prestes a ativar uma configuração SMTP. Primeiro, desativaremos o provedor ativo atual e depois ativaremos esta configuração. Tem certeza?",
"DEACTIVATE_WARN_TITLE": "Desativar configuração SMTP",
"DEACTIVATE_WARN_DESCRIPTION": "Você está prestes a desativar uma configuração SMTP. Tem certeza?",
"DEACTIVATED": "A configuração SMTP foi desativada",
"DELETE_TITLE": "Excluir configuração SMTP",
"DELETE_DESCRIPTION": "Você está prestes a excluir uma configuração. Confirme esta ação digitando o nome do remetente",
"DELETED": "A configuração SMTP foi excluída",
"SENDER": "Digite {{ value }} para excluir esta configuração SMTP."
}
},
"CREATE": {
"TITLE": "Adicionar provedor SMTP",
"DESCRIPTION": "Selecione um ou mais dos seguintes fornecedores.",
"STEPS": {
"TITLE": "Adicionar {{ value }} provedor SMTP",
"CREATE_DESC_TITLE": "Insira suas configurações SMTP de {{ value }} passo a passo",
"CURRENT_DESC_TITLE": "Estas são suas configurações de SMTP",
"PROVIDER_SETTINGS": "Configurações do provedor SMTP",
"SENDER_SETTINGS": "Configurações do remetente",
"TEST_SETTINGS": "Testar configurações de SMTP"
}
},
"DETAIL": {
"TITLE": "Configurações do provedor SMTP"
},
"EMPTY": "Nenhum provedor SMTP disponível",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Aplicações",
"COMPLIANCE": "Conformidade OIDC",

View File

@@ -1425,6 +1425,7 @@
},
"SMTP": {
"TITLE": "Настройки SMTP",
"DESCRIPTION": "Описание",
"SENDERADDRESS": "Адрес электронной почты отправителя",
"SENDERNAME": "Имя отправителя",
"HOSTANDPORT": "Хост и порт",
@@ -1434,6 +1435,7 @@
"PASSWORDSET": "Пароль SMTP был успешно установлен.",
"TLS": "Безопасность транспортного уровня (TLS)",
"SAVED": "Успешно сохранено!",
"NOCHANGES": "Без изменений!",
"REQUIREDWARN": "Для того, чтобы отправлять уведомления с вашего домена, вам необходимо ввести свои данные SMTP."
},
"SMS": {
@@ -2331,6 +2333,48 @@
"1": "Разрешён"
}
},
"SMTP": {
"LIST": {
"TITLE": "SMTP-провайдер",
"DESCRIPTION": "Это поставщики SMTP для вашего экземпляра Zitadel. Активируйте тот, который вы хотите использовать для отправки уведомлений вашим пользователям.",
"EMPTY": "SMTP-провайдер не доступен",
"ACTIVATED": "Активировано",
"ACTIVATE": "Активировать провайдера",
"DEACTIVATE": "Деактивировать провайдера",
"TYPE": "Тип",
"DIALOG": {
"ACTIVATED": "Конфигурация SMTP активирована",
"ACTIVATE_WARN_TITLE": "Активируйте конфигурацию SMTP",
"ACTIVATE_WARN_DESCRIPTION": "Вы собираетесь активировать конфигурацию SMTP. Сначала мы деактивируем текущего активного провайдера, а затем активируем эту конфигурацию. Вы уверены?",
"DEACTIVATE_WARN_TITLE": "Деактивировать конфигурацию SMTP",
"DEACTIVATE_WARN_DESCRIPTION": "Вы собираетесь деактивировать конфигурацию SMTP. Вы уверены?",
"DEACTIVATED": "Конфигурация SMTP деактивирована",
"DELETE_TITLE": "Удалить конфигурацию SMTP",
"DELETE_DESCRIPTION": "Вы собираетесь удалить конфигурацию. Подтвердите это действие, введя имя отправителя.",
"DELETED": "Конфигурация SMTP удалена.",
"SENDER": "Введите {{ value }}, чтобы удалить эту конфигурацию SMTP."
}
},
"CREATE": {
"TITLE": "Добавить SMTP-провайдера",
"DESCRIPTION": "Выберите одного или нескольких из следующих поставщиков.",
"STEPS": {
"TITLE": "Добавить {{ value }} SMTP-провайдера",
"CREATE_DESC_TITLE": "Введите {{ value }} настройки SMTP шаг за шагом.",
"CURRENT_DESC_TITLE": "Это ваши настройки SMTP",
"PROVIDER_SETTINGS": "Настройки SMTP-провайдера",
"SENDER_SETTINGS": "Настройки отправителя",
"TEST_SETTINGS": "Проверка настроек SMTP"
}
},
"DETAIL": {
"TITLE": "Настройки SMTP-провайдера"
},
"EMPTY": "Нет доступного поставщика SMTP",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "Приложения",
"COMPLIANCE": "Соответствие OIDC",

View File

@@ -1380,6 +1380,8 @@
}
},
"SMTP": {
"TITLE": "SMTP 设置",
"DESCRIPTION": "描述",
"SENDERADDRESS": "发件人地址",
"SENDERNAME": "发件人名称",
"REPLYTOADDRESS": "Reply-to 地址",
@@ -1390,6 +1392,7 @@
"PASSWORDSET": "SMTP 密码设置成功。",
"TLS": "使用安全传输层 (TLS)",
"SAVED": "保存成功!",
"NOCHANGES": "没有变化!",
"REQUIREDWARN": "要从您的域发送通知,您必须输入您的 SMTP 数据。"
},
"SMS": {
@@ -2217,6 +2220,48 @@
"1": "允许"
}
},
"SMTP": {
"LIST": {
"TITLE": "SMTP 提供商",
"DESCRIPTION": "这些是您的 Zitadel 实例的 SMTP 提供商。激活您想要用来向用户发送通知的通知。",
"EMPTY": "没有可用的 SMTP 提供商",
"ACTIVATED": "活性",
"ACTIVATE": "激活提供商",
"DEACTIVATE": "停用提供商",
"TYPE": "类型",
"DIALOG": {
"ACTIVATED": "SMTP 配置已激活",
"ACTIVATE_WARN_TITLE": "激活 SMTP 配置",
"ACTIVATE_WARN_DESCRIPTION": "您即将激活 SMTP 配置。首先,我们将停用当前活动的提供程序,然后激活此配置。你确定吗?",
"DEACTIVATE_WARN_TITLE": "停用 SMTP 配置",
"DEACTIVATE_WARN_DESCRIPTION": "您即将停用 SMTP 配置。你确定吗?",
"DEACTIVATED": "SMTP 配置已停用",
"DELETE_TITLE": "删除 SMTP 配置",
"DELETE_DESCRIPTION": "您将要删除一个配置。输入发件人姓名确认此操作",
"DELETED": "SMTP 配置已被删除",
"SENDER": "输入 {{ value }},删除此 SMTP 配置。"
}
},
"CREATE": {
"TITLE": "添加 SMTP 提供商",
"DESCRIPTION": "选择以下一个或多个提供商。",
"STEPS": {
"TITLE": "添加 {{ value }} SMTP 提供商",
"CREATE_DESC_TITLE": "逐步输入您的 {{ value }} SMTP 设置",
"CURRENT_DESC_TITLE": "这些是您的 SMTP 设置",
"PROVIDER_SETTINGS": "SMTP 提供商设置",
"SENDER_SETTINGS": "发件人设置",
"TEST_SETTINGS": "测试 SMTP 设置"
}
},
"DETAIL": {
"TITLE": "SMTP 提供商设置"
},
"EMPTY": "没有可用的 SMTP 提供商",
"STEPS": {
"SENDGRID": {}
}
},
"APP": {
"LIST": "应用",
"COMPLIANCE": "OIDC 兼容性",

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="256px" height="299px" viewBox="0 0 256 299" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<path d="M60.556,47.602 L0,144.01 L60.556,240.434 L61.612,239.681 L60.837,47.8 L60.556,47.602" fill="#876929"></path>
<path d="M128.187,223.105 L60.556,240.434 L60.556,47.602 L128.187,64.927 L128.187,223.105" fill="#D9A741"></path>
<path d="M255.979,71.868 L223.379,77.259 L148.538,0 L111.331,16.292 L116.239,25.445 L89.906,35.971 L89.906,279.399 L128.186,298.552 L128.823,298.053 L128.234,47.818 L209.376,170.786 L255.979,71.868" fill="#876929"></path>
<path d="M148.538,0 L248.217,49.837 L208.8,121.357 L148.538,0" fill="#D9A741"></path>
<path d="M255.975,71.868 L256,234.596 L128.187,298.552 L128.17,20.683 L208.8,166.974 L255.975,71.868" fill="#D9A741"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 927 B

View File

@@ -0,0 +1,3 @@
<svg width="1000" height="295" viewBox="0 0 1000 295" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M820.28 182.338C820.28 137.755 848.604 106.4 888.892 106.4C929.18 106.4 957.956 137.737 957.956 182.338C957.956 226.939 929.187 256.5 888.892 256.5C848.598 256.5 820.28 225.588 820.28 182.338ZM778.224 182.338C778.224 248.12 824.262 294.479 888.886 294.479C953.51 294.479 1000 248.12 1000 182.338C1000 116.556 953.962 68.4399 888.886 68.4399C823.81 68.4399 778.224 115.686 778.224 182.338ZM563.521 71.0853L650.292 291.821H691.025L777.791 71.0853H733.966L671.104 241.498H670.214L607.352 71.0853H563.521ZM394.856 174.383C397.508 133.76 424.515 106.4 461.261 106.4C493.128 106.4 517.037 126.712 520.58 157.179H447.089C420.973 157.179 406.801 160.269 396.191 174.402H394.856V174.39V174.383ZM352.805 181.006C352.805 246.788 399.289 294.46 463.468 294.46C506.854 294.46 544.916 272.391 561.295 237.502L525.885 219.835C513.494 242.792 489.585 256.482 463.468 256.482C432.028 256.482 403.704 232.637 403.704 209.679C403.704 197.766 411.673 192.457 423.18 192.457H563.502V180.544C563.502 114.317 521.007 68.4029 459.925 68.4029C398.844 68.4029 352.799 115.649 352.799 180.988M232.399 291.796H272.242V156.285C272.242 127.149 290.382 106.394 315.627 106.394C326.256 106.394 337.311 109.927 342.635 114.774C346.623 104.174 352.818 93.5923 362.111 82.9924C351.482 74.1684 333.342 68.4153 315.627 68.4153C266.937 68.4153 232.399 104.618 232.399 156.267V291.809V291.796ZM39.843 145.698V37.9598H105.358C127.486 37.9598 142.103 50.7611 142.103 70.185C142.103 92.2542 123.072 109.033 84.1191 121.834C57.5571 130.214 45.6116 137.281 41.1785 145.679L39.843 145.692V145.698ZM39.843 253.861V208.835C39.843 188.967 56.6668 169.543 80.1311 162.032C100.943 154.966 118.193 147.899 132.81 140.407C152.286 151.895 164.232 171.744 164.232 192.5C164.232 227.814 130.584 253.861 84.9909 253.861H39.843ZM0 291.821H88.5337C155.829 291.821 206.282 249.884 206.282 194.257C206.282 163.79 190.794 136.43 163.341 118.763C177.513 104.63 184.153 88.2955 184.153 68.4276C184.153 27.3784 154.493 0 109.791 0H0V291.821Z" fill="#0B996E"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><rect fill="#ffe01b" height="512" rx="15%" width="512"/><path d="m418 306-6-17s25-38-37-51c0 0 4-47-18-69 48-47 37-118-72-72-56-107-272 144-182 184-9 12-9 72 53 78 42 90 144 96 203 69s93-113 59-122zm-263 40c-51-5-56-75-12-82s55 86 12 82zm-15-95c-14 0-31 19-31 19-68-33 123-252 164-167 0 0-100 48-133 148zm200 85c0-4-21 6-59-7 3-21 48 18 123-33l6 21c28-5 0 90-90 89-73-1-96-76-56-117 8-8-29-24-22-59 3-15 16-37 49-31s40-24 62-13 9 53 12 59 35 7 41 24-41 54-114 44c-17-2-27 20-16 34 22 32 112 11 127-20-38 29-116 40-122 9 22 10 59 4 59 0zm-131-158c22-27 51-43 51-43l-6 15s21-16 44-16l-8 8c26 1 37 11 37 11s-61-18-118 25zm135 39c13-1 9 29 9 29h-8s-14-28-1-29zm-59 33c-9 1-19 6-18 2 4-16 41-12 40 2s-9-6-22-4zm21 12c1 2-7 0-13 1s-12 4-12 2 23-11 25-3zm20 3c3-6 15 0 12 6s-15 0-12-6zm25 2c-6 0-6-13 0-13s6 14 0 14zm-180 53c3 3-6 9-13 4s8-29-10-35-13 17-18 14 7-35 28-22-6 33 6 39 5-2 7 0z" fill="#1e1e1e"/></svg>

After

Width:  |  Height:  |  Size: 969 B

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
<style type="text/css">
.st0{fill:#C12126;}
</style>
<path class="st0" d="M493,305.7c-88.9,0-161,72.1-161,161c0,88.9,72.1,161,161,161c88.9,0,161-72.1,161-161
C654,377.8,582,305.7,493,305.7z M242,466.7c0-138.7,112.4-251,251-251c138.7,0,251.1,112.4,251.1,251c0,9.2-0.5,18.2-1.4,27.1
c-1.9,24.5,16.1,43.2,40.4,43.2c41.3,0,45.7-53.2,45.7-70.3c0-185.4-150.3-335.6-335.6-335.6S157.4,281.4,157.4,466.7
c0,185.4,150.3,335.6,335.6,335.6c98.4,0,187-42.4,248.4-109.9l69,57.9c-77.9,87.1-191.3,142-317.4,142
c-235.1,0-425.7-190.6-425.7-425.7S257.9,41,493,41c235.1,0,425.7,190.6,425.7,425.7c0,94.5-45,171.2-135.4,171.2
c-39.8,0-64-18.2-77.2-38.6C661.9,670.5,583,717.8,493,717.8C354.4,717.8,242,605.4,242,466.7z M493,393.1c40.7,0,73.7,33,73.7,73.7
c0,40.7-33,73.7-73.7,73.7c-40.7,0-73.7-33-73.7-73.7S452.3,393.1,493,393.1z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256px" height="255px" viewBox="0 0 256 255" version="1.1" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid">
<title>Mailjet</title>
<g>
<polygon fill="#9585F4" points="1.42108547e-14 97.9914749 93.4083546 140.330776 112.177323 121.670929 64.3819267 99.9556692 212.56948 43.2122762 155.607843 190.745098 134.001705 143.386189 115.123615 162.155158 116.105712 164.337596 157.462916 255.017903 256 -7.10542736e-15"></polygon>
</g>
</svg>

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>

After

Width:  |  Height:  |  Size: 309 B

View File

@@ -72,6 +72,9 @@
@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 'src/app/modules/smtp-table/smtp-table.component.scss';
@import 'src/app/modules/smtp-provider/smtp-provider.scss';
@import 'src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.scss';
@import './styles/codemirror.scss';
@import 'src/app/components/copy-row/copy-row.component.scss';
@import 'src/app/modules/providers/provider-next/provider-next.component.scss';
@@ -85,6 +88,8 @@
@include header-theme($theme);
@include app-type-radio-theme($theme);
@include idp-table-theme($theme);
@include smtp-table-theme($theme);
@include smtp-provider-theme($theme);
@include events-theme($theme);
@include projects-theme($theme);
@include grants-theme($theme);
@@ -153,4 +158,5 @@
@include domain-verification-theme($theme);
@include copy-row-theme($theme);
@include provider-next-theme($theme);
@include smtp-settings-theme($theme);
}