Skip to content

Commit

Permalink
feat: SMTP Templates (#6932)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
4 people committed Apr 11, 2024
1 parent e2f0cd0 commit d229da6
Show file tree
Hide file tree
Showing 93 changed files with 6,349 additions and 6,122 deletions.
2 changes: 2 additions & 0 deletions console/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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,
Expand All @@ -34,9 +36,9 @@ import { MatDialogModule } from '@angular/material/dialog';
FormFieldModule,
WarnDialogModule,
MatSelectModule,
MatDialogModule,
MatProgressSpinnerModule,
MatSelectModule,
MatDialogModule,
TranslateModule,
],
exports: [NotificationSMSProviderComponent],
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
) {}

Expand Down
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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;
}
.cnsl-smtp-table-wrapper {
display: block;
}

.smtp-checkbox {
max-width: 400px;
display: block;
margin: 1rem 0;
}
.new-smtp-wrapper {
display: grid;
row-gap: 1.5rem;
column-gap: 1.5rem;
box-sizing: border-box;
width: 100%;
grid-template-columns: 1fr;

.set-password-btn {
margin-bottom: 1rem;
}
@media only screen and (min-width: 700px) {
grid-template-columns: 1fr 1fr;
}

.general-btn-container {
display: flex;
justify-content: flex-start;
@media only screen and (min-width: 1000px) {
grid-template-columns: 1fr 1fr 1fr;
}

.save-button {
display: block;
@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;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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>;

Expand Down

0 comments on commit d229da6

Please sign in to comment.