-
-
-
- {{ 'DESCRIPTIONS.ACTIONS.ACTIONSTWO_NOTE' | translate }}
-
-
{{ 'DESCRIPTIONS.ACTIONS.DESCRIPTION' | translate }}
+
+
{{ 'ORG.PAGES.LIST' | translate }}
+
{{ 'ORG.PAGES.LISTDESCRIPTION' | translate }}
-
{{ 'FLOWS.ACTIONSMAX' | translate: { value: maxActions } }}
-
+
+
+ actions
-
-
-
-
-
-
-
-
{{ 'DESCRIPTIONS.ACTIONS.FLOWS.TITLE' | translate }}
-
-
-
- {{ 'DESCRIPTIONS.ACTIONS.FLOWS.DESCRIPTION' | translate }}
-
-
-
-
- {{ 'FLOWS.FLOWTYPE' | translate }}
-
-
- {{ type.name?.localizedMessage }}
-
-
-
-
-
-
-
-
-
- {{ flow.type?.name?.localizedMessage }}
-
-
-
-
-
-
- {{ trigger.triggerType?.name?.localizedMessage }}
-
-
-
-
-
-
-
- {{ action.name }}
-
-
- {{ 'FLOWS.STATES.' + action.state | translate }}
-
-
-
-
-
-
-
-
+ targets
+
+
diff --git a/console/src/app/pages/actions/actions.component.scss b/console/src/app/pages/actions/actions.component.scss
index f15ca60676..1735498b9f 100644
--- a/console/src/app/pages/actions/actions.component.scss
+++ b/console/src/app/pages/actions/actions.component.scss
@@ -1,186 +1,7 @@
-.actions-title-row {
- display: flex;
- align-items: center;
-
- h1 {
- margin: 0;
- }
-
- a {
- .icon {
- font-size: 1.2rem;
- height: 1.2rem;
- width: 1.2rem;
- }
- }
+h1 {
+ margin: 0;
}
-@mixin actions-theme($theme) {
- $foreground: map-get($theme, foreground);
- $background: map-get($theme, background);
- $is-dark-theme: map-get($theme, is-dark);
- $primary: map-get($theme, primary);
- $primary-color: map-get($primary, 500);
-
- .actions-enlarged-container {
- h1 {
- margin: 0;
- }
-
- .desc {
- margin-bottom: 2rem;
- font-size: 14px;
- }
-
- .title-section {
- display: flex;
- align-items: center;
- margin-top: 3rem;
- margin-bottom: 1rem;
-
- h2 {
- margin: 0;
- }
-
- i {
- margin-left: 0.5rem;
- }
- }
-
- .actions-flow {
- display: flex;
- flex-direction: column;
- max-width: 1000px;
- position: relative;
-
- .formfield {
- max-width: 300px;
- }
-
- .flow-type {
- margin: 0.5rem 0;
- display: flex;
- align-items: center;
- justify-content: flex-start;
- padding: 0 1.5rem;
-
- .type-icon {
- color: $primary-color;
- }
-
- .type-button-icon,
- .type-icon,
- span {
- margin-right: 1rem;
- }
-
- .type-icon,
- .type-button-icon {
- position: relative;
- }
- }
-
- .trigger-wrapper {
- position: relative;
-
- .trigger {
- display: flex;
- align-items: center;
- position: relative;
-
- .trigger-top {
- display: flex;
- align-items: center;
- margin-bottom: 0.5rem;
- padding-left: 7px;
-
- .fill-space {
- flex: 1;
- }
- }
-
- .icon {
- margin-right: 1rem;
- color: $primary-color;
- }
-
- .fill-space {
- flex: 1;
- }
-
- .flow-action-wrapper {
- padding: 0 0.5rem;
- margin: 0;
-
- .flow-action {
- display: flex;
- align-items: center;
- font-size: 14px;
- padding: 0.5rem 0;
- cursor: move;
-
- .flow-action-name {
- margin-right: 1rem;
- }
-
- .fill-space {
- flex: 1;
- }
-
- i {
- margin-right: 0.5rem;
- }
- }
-
- .state {
- margin-left: 1rem;
- }
- }
- }
- }
-
- .actions-topbottomline {
- position: absolute;
- top: 26px;
- bottom: 1.5rem;
- left: 35px;
- width: 2px;
- z-index: 0;
- background-color: $primary-color;
- }
-
- .add-btn {
- display: flex;
- align-items: center;
- align-self: flex-start;
- margin: 1rem 0;
- }
- }
-
- .cdk-drag-preview {
- color: white;
- display: flex;
- align-items: center;
- font-size: 14px;
- border-radius: 0.5rem;
- padding: 0 0.5rem;
- background-color: $primary-color;
- box-shadow:
- 0 5px 5px -3px rgba(0, 0, 0, 0.2),
- 0 8px 10px 1px rgba(0, 0, 0, 0.14),
- 0 3px 14px 2px rgba(0, 0, 0, 0.12);
-
- i {
- margin-right: 0.5rem;
- }
- }
-
- .cdk-drag-placeholder {
- opacity: 0;
- }
-
- .cdk-drag-animating {
- transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
- }
- }
+.org-desc {
+ font-size: 14px;
}
diff --git a/console/src/app/pages/actions/actions.component.spec.ts b/console/src/app/pages/actions/actions.component.spec.ts
index 5b4d68e7de..f8c586f23a 100644
--- a/console/src/app/pages/actions/actions.component.spec.ts
+++ b/console/src/app/pages/actions/actions.component.spec.ts
@@ -1,19 +1,19 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
-import { ActionsComponent } from './actions.component';
+import { OrgListComponent } from './actions.component';
-describe('ActionsComponent', () => {
- let component: ActionsComponent;
- let fixture: ComponentFixture
;
+describe('OrgListComponent', () => {
+ let component: OrgListComponent;
+ let fixture: ComponentFixture;
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ActionsComponent],
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [OrgListComponent],
}).compileComponents();
- });
+ }));
beforeEach(() => {
- fixture = TestBed.createComponent(ActionsComponent);
+ fixture = TestBed.createComponent(OrgListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/console/src/app/pages/actions/actions.component.ts b/console/src/app/pages/actions/actions.component.ts
index f926e7b819..7a139379e1 100644
--- a/console/src/app/pages/actions/actions.component.ts
+++ b/console/src/app/pages/actions/actions.component.ts
@@ -1,180 +1,28 @@
-import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
-import { Component, DestroyRef } from '@angular/core';
-import { UntypedFormControl } from '@angular/forms';
-import { MatDialog } from '@angular/material/dialog';
-import { ActionKeysType } from 'src/app/modules/action-keys/action-keys.component';
-import { InfoSectionType } from 'src/app/modules/info-section/info-section.component';
-import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
-import { Action, ActionState, Flow, FlowType, TriggerType } from 'src/app/proto/generated/zitadel/action_pb';
-import { SetTriggerActionsRequest } from 'src/app/proto/generated/zitadel/management_pb';
+import { Component } from '@angular/core';
+import { enterAnimations } from 'src/app/animations';
+import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
-import { ManagementService } from 'src/app/services/mgmt.service';
-import { ToastService } from 'src/app/services/toast.service';
-import { AddFlowDialogComponent } from './add-flow-dialog/add-flow-dialog.component';
-import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+const ACTIONS: SidenavSetting = { id: 'general', i18nKey: 'MENU.ACTIONS' };
+const TARGETS: SidenavSetting = { id: 'roles', i18nKey: 'MENU.TARGETS' };
@Component({
selector: 'cnsl-actions',
templateUrl: './actions.component.html',
styleUrls: ['./actions.component.scss'],
+ animations: [enterAnimations],
})
export class ActionsComponent {
- protected flow!: Flow.AsObject;
+ public settingsList: SidenavSetting[] = [ACTIONS, TARGETS];
+ public currentSetting = this.settingsList[0];
- protected typeControl: UntypedFormControl = new UntypedFormControl();
-
- protected typesForSelection: FlowType.AsObject[] = [];
-
- protected selection: Action.AsObject[] = [];
- protected InfoSectionType = InfoSectionType;
- protected ActionKeysType = ActionKeysType;
-
- protected maxActions: number | null = null;
- protected ActionState = ActionState;
- constructor(
- private mgmtService: ManagementService,
- breadcrumbService: BreadcrumbService,
- private dialog: MatDialog,
- private toast: ToastService,
- destroyRef: DestroyRef,
- ) {
- const bread: Breadcrumb = {
- type: BreadcrumbType.ORG,
- routerLink: ['/org'],
- };
- breadcrumbService.setBreadcrumb([bread]);
-
- this.getFlowTypes().then();
-
- this.typeControl.valueChanges.pipe(takeUntilDestroyed(destroyRef)).subscribe((value) => {
- this.loadFlow((value as FlowType.AsObject).id);
- });
- }
-
- private async getFlowTypes(): Promise {
- try {
- let resp = await this.mgmtService.listFlowTypes();
- this.typesForSelection = resp.resultList;
- if (!this.flow && resp.resultList[0]) {
- const type = resp.resultList[0];
- this.typeControl.setValue(type);
- }
- } catch (error) {
- this.toast.showError(error);
- }
- }
-
- private loadFlow(id: string) {
- this.mgmtService.getFlow(id).then((flowResponse) => {
- if (flowResponse.flow) {
- this.flow = flowResponse.flow;
- }
- });
- }
-
- public clearFlow(id: string): void {
- const dialogRef = this.dialog.open(WarnDialogComponent, {
- data: {
- confirmKey: 'ACTIONS.CLEAR',
- cancelKey: 'ACTIONS.CANCEL',
- titleKey: 'FLOWS.DIALOG.CLEAR.TITLE',
- descriptionKey: 'FLOWS.DIALOG.CLEAR.DESCRIPTION',
- },
- width: '400px',
+ constructor(breadcrumbService: BreadcrumbService) {
+ const iamBread = new Breadcrumb({
+ type: BreadcrumbType.INSTANCE,
+ name: 'Instance',
+ routerLink: ['/instance'],
});
- dialogRef.afterClosed().subscribe((resp) => {
- if (resp) {
- this.mgmtService
- .clearFlow(id)
- .then(() => {
- this.toast.showInfo('FLOWS.FLOWCLEARED', true);
- this.loadFlow(id);
- })
- .catch((error: any) => {
- this.toast.showError(error);
- });
- }
- });
- }
-
- protected openAddTrigger(flow: FlowType.AsObject, trigger?: TriggerType.AsObject): void {
- const dialogRef = this.dialog.open(AddFlowDialogComponent, {
- data: {
- flowType: flow,
- actions: this.selection && this.selection.length ? this.selection : [],
- },
- width: '400px',
- });
-
- dialogRef.afterClosed().subscribe((req: SetTriggerActionsRequest) => {
- if (req) {
- this.mgmtService
- .setTriggerActions(req.getActionIdsList(), req.getFlowType(), req.getTriggerType())
- .then(() => {
- this.toast.showInfo('FLOWS.FLOWCHANGED', true);
- this.loadFlow(flow.id);
- })
- .catch((error: any) => {
- this.toast.showError(error);
- });
- }
- });
- }
-
- drop(triggerActionsListIndex: number, array: any[], event: CdkDragDrop) {
- moveItemInArray(array, event.previousIndex, event.currentIndex);
- this.saveFlow(triggerActionsListIndex);
- }
-
- saveFlow(index: number) {
- if (
- this.flow.type &&
- this.flow.triggerActionsList &&
- this.flow.triggerActionsList[index] &&
- this.flow.triggerActionsList[index]?.triggerType
- ) {
- this.mgmtService
- .setTriggerActions(
- this.flow.triggerActionsList[index].actionsList.map((action) => action.id),
- this.flow.type.id,
- this.flow.triggerActionsList[index].triggerType?.id ?? '',
- )
- .then(() => {
- this.toast.showInfo('FLOWS.TOAST.ACTIONSSET', true);
- })
- .catch((error) => {
- this.toast.showError(error);
- });
- }
- }
-
- protected removeTriggerActionsList(index: number) {
- if (this.flow.type && this.flow.triggerActionsList && this.flow.triggerActionsList[index]) {
- const dialogRef = this.dialog.open(WarnDialogComponent, {
- data: {
- confirmKey: 'ACTIONS.CLEAR',
- cancelKey: 'ACTIONS.CANCEL',
- titleKey: 'FLOWS.DIALOG.REMOVEACTIONSLIST.TITLE',
- descriptionKey: 'FLOWS.DIALOG.REMOVEACTIONSLIST.DESCRIPTION',
- },
- width: '400px',
- });
-
- dialogRef.afterClosed().subscribe((resp) => {
- if (resp) {
- this.mgmtService
- .setTriggerActions([], this.flow?.type?.id ?? '', this.flow.triggerActionsList[index].triggerType?.id ?? '')
- .then(() => {
- this.toast.showInfo('FLOWS.TOAST.ACTIONSSET', true);
- this.loadFlow(this.flow?.type?.id ?? '');
- })
- .catch((error) => {
- this.toast.showError(error);
- });
- }
- });
- }
+ breadcrumbService.setBreadcrumb([iamBread]);
}
}
diff --git a/console/src/app/pages/actions/actions.module.ts b/console/src/app/pages/actions/actions.module.ts
index c5da8663fa..112ff8eede 100644
--- a/console/src/app/pages/actions/actions.module.ts
+++ b/console/src/app/pages/actions/actions.module.ts
@@ -1,68 +1,16 @@
-import { DragDropModule } from '@angular/cdk/drag-drop';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { MatButtonModule } from '@angular/material/button';
-import { MatCheckboxModule } from '@angular/material/checkbox';
-import { MatDialogModule } from '@angular/material/dialog';
-import { MatIconModule } from '@angular/material/icon';
-import { MatSelectModule } from '@angular/material/select';
-import { MatTableModule } from '@angular/material/table';
-import { MatTooltipModule } from '@angular/material/tooltip';
-import { CodemirrorModule } from '@ctrl/ngx-codemirror';
import { TranslateModule } from '@ngx-translate/core';
-import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
-import { ActionKeysModule } from 'src/app/modules/action-keys/action-keys.module';
-import { CardModule } from 'src/app/modules/card/card.module';
-import { FormFieldModule } from 'src/app/modules/form-field/form-field.module';
-import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
-import { InputModule } from 'src/app/modules/input/input.module';
-import { PaginatorModule } from 'src/app/modules/paginator/paginator.module';
-import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
-import { TableActionsModule } from 'src/app/modules/table-actions/table-actions.module';
-import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module';
-import { DurationToSecondsPipeModule } from 'src/app/pipes/duration-to-seconds-pipe/duration-to-seconds-pipe.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 { OrgTableModule } from 'src/app/modules/org-table/org-table.module';
-import { ActionTableComponent } from './action-table/action-table.component';
import { ActionsRoutingModule } from './actions-routing.module';
import { ActionsComponent } from './actions.component';
-import { AddActionDialogComponent } from './add-action-dialog/add-action-dialog.component';
-import { AddFlowDialogComponent } from './add-flow-dialog/add-flow-dialog.component';
+import { MetaLayoutModule } from 'src/app/modules/meta-layout/meta-layout.module';
+import { SidenavModule } from 'src/app/modules/sidenav/sidenav.module';
@NgModule({
- declarations: [ActionsComponent, ActionTableComponent, AddActionDialogComponent, AddFlowDialogComponent],
- imports: [
- CommonModule,
- FormsModule,
- ActionsRoutingModule,
- TranslateModule,
- MatDialogModule,
- RefreshTableModule,
- MatTableModule,
- PaginatorModule,
- MatButtonModule,
- ReactiveFormsModule,
- MatIconModule,
- DurationToSecondsPipeModule,
- TimestampToDatePipeModule,
- LocalizedDatePipeModule,
- HasRoleModule,
- ActionKeysModule,
- MatTooltipModule,
- CardModule,
- MatCheckboxModule,
- InputModule,
- FormFieldModule,
- MatSelectModule,
- WarnDialogModule,
- DragDropModule,
- InfoSectionModule,
- HasRolePipeModule,
- TableActionsModule,
- CodemirrorModule,
- ],
+ declarations: [ActionsComponent],
+ imports: [CommonModule, ActionsRoutingModule, OrgTableModule, TranslateModule, MetaLayoutModule, SidenavModule],
+ exports: [ActionsComponent],
})
export default class ActionsModule {}
diff --git a/console/src/app/pages/home/home.component.ts b/console/src/app/pages/home/home.component.ts
index f84e91fc05..62fcbea7c5 100644
--- a/console/src/app/pages/home/home.component.ts
+++ b/console/src/app/pages/home/home.component.ts
@@ -27,8 +27,8 @@ export class HomeComponent {
public themeService: ThemeService,
) {
const bread: Breadcrumb = {
- type: BreadcrumbType.ORG,
- routerLink: ['/org'],
+ type: BreadcrumbType.INSTANCE,
+ routerLink: ['/'],
};
breadcrumbService.setBreadcrumb([bread]);
diff --git a/console/src/app/pages/instance/instance.component.ts b/console/src/app/pages/instance/instance.component.ts
index e52cdd7198..f6e56a808c 100644
--- a/console/src/app/pages/instance/instance.component.ts
+++ b/console/src/app/pages/instance/instance.component.ts
@@ -33,10 +33,7 @@ import {
VIEWS,
FAILEDEVENTS,
EVENTS,
- ORGANIZATIONS,
FEATURESETTINGS,
- ACTIONS,
- ACTIONS_TARGETS,
} from 'src/app/modules/settings-list/settings';
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
@@ -58,10 +55,7 @@ export class InstanceComponent {
protected id: string = '';
protected readonly defaultSettingsList: SidenavSetting[] = [
- ORGANIZATIONS,
FEATURESETTINGS,
- ACTIONS,
- ACTIONS_TARGETS,
// notifications
// { showWarn: true, ...NOTIFICATIONS },
NOTIFICATIONS,
diff --git a/console/src/app/pages/actions/action-table/action-table.component.html b/console/src/app/pages/org-actions/action-table/action-table.component.html
similarity index 100%
rename from console/src/app/pages/actions/action-table/action-table.component.html
rename to console/src/app/pages/org-actions/action-table/action-table.component.html
diff --git a/console/src/app/pages/actions/action-table/action-table.component.scss b/console/src/app/pages/org-actions/action-table/action-table.component.scss
similarity index 100%
rename from console/src/app/pages/actions/action-table/action-table.component.scss
rename to console/src/app/pages/org-actions/action-table/action-table.component.scss
diff --git a/console/src/app/pages/actions/action-table/action-table.component.spec.ts b/console/src/app/pages/org-actions/action-table/action-table.component.spec.ts
similarity index 100%
rename from console/src/app/pages/actions/action-table/action-table.component.spec.ts
rename to console/src/app/pages/org-actions/action-table/action-table.component.spec.ts
diff --git a/console/src/app/pages/actions/action-table/action-table.component.ts b/console/src/app/pages/org-actions/action-table/action-table.component.ts
similarity index 100%
rename from console/src/app/pages/actions/action-table/action-table.component.ts
rename to console/src/app/pages/org-actions/action-table/action-table.component.ts
diff --git a/console/src/app/pages/org-actions/actions-routing.module.ts b/console/src/app/pages/org-actions/actions-routing.module.ts
new file mode 100644
index 0000000000..8fcd4b5f12
--- /dev/null
+++ b/console/src/app/pages/org-actions/actions-routing.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { ActionsComponent } from './actions.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: ActionsComponent,
+ },
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class ActionsRoutingModule {}
diff --git a/console/src/app/pages/org-actions/actions.component.html b/console/src/app/pages/org-actions/actions.component.html
new file mode 100644
index 0000000000..af936e2351
--- /dev/null
+++ b/console/src/app/pages/org-actions/actions.component.html
@@ -0,0 +1,107 @@
+
+
+
+
+ {{ 'DESCRIPTIONS.ACTIONS.ACTIONSTWO_NOTE' | translate }}
+
+
{{ 'DESCRIPTIONS.ACTIONS.DESCRIPTION' | translate }}
+
+
{{ 'FLOWS.ACTIONSMAX' | translate: { value: maxActions } }}
+
+
+
+
+
+
+
+
+
+
{{ 'DESCRIPTIONS.ACTIONS.FLOWS.TITLE' | translate }}
+
+
+
+
{{ 'DESCRIPTIONS.ACTIONS.FLOWS.DESCRIPTION' | translate }}
+
+
+
+
+ {{ 'FLOWS.FLOWTYPE' | translate }}
+
+
+ {{ type.name?.localizedMessage }}
+
+
+
+
+
+
+
+
+
+ {{ flow.type?.name?.localizedMessage }}
+
+
+
+
+
+
+ {{ trigger.triggerType?.name?.localizedMessage }}
+
+
+
+
+
+
+
+ {{ action.name }}
+
+
+ {{ 'FLOWS.STATES.' + action.state | translate }}
+
+
+
+
+
+
+
+
+
+
diff --git a/console/src/app/pages/org-actions/actions.component.scss b/console/src/app/pages/org-actions/actions.component.scss
new file mode 100644
index 0000000000..f15ca60676
--- /dev/null
+++ b/console/src/app/pages/org-actions/actions.component.scss
@@ -0,0 +1,186 @@
+.actions-title-row {
+ display: flex;
+ align-items: center;
+
+ h1 {
+ margin: 0;
+ }
+
+ a {
+ .icon {
+ font-size: 1.2rem;
+ height: 1.2rem;
+ width: 1.2rem;
+ }
+ }
+}
+
+@mixin actions-theme($theme) {
+ $foreground: map-get($theme, foreground);
+ $background: map-get($theme, background);
+ $is-dark-theme: map-get($theme, is-dark);
+ $primary: map-get($theme, primary);
+ $primary-color: map-get($primary, 500);
+
+ .actions-enlarged-container {
+ h1 {
+ margin: 0;
+ }
+
+ .desc {
+ margin-bottom: 2rem;
+ font-size: 14px;
+ }
+
+ .title-section {
+ display: flex;
+ align-items: center;
+ margin-top: 3rem;
+ margin-bottom: 1rem;
+
+ h2 {
+ margin: 0;
+ }
+
+ i {
+ margin-left: 0.5rem;
+ }
+ }
+
+ .actions-flow {
+ display: flex;
+ flex-direction: column;
+ max-width: 1000px;
+ position: relative;
+
+ .formfield {
+ max-width: 300px;
+ }
+
+ .flow-type {
+ margin: 0.5rem 0;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ padding: 0 1.5rem;
+
+ .type-icon {
+ color: $primary-color;
+ }
+
+ .type-button-icon,
+ .type-icon,
+ span {
+ margin-right: 1rem;
+ }
+
+ .type-icon,
+ .type-button-icon {
+ position: relative;
+ }
+ }
+
+ .trigger-wrapper {
+ position: relative;
+
+ .trigger {
+ display: flex;
+ align-items: center;
+ position: relative;
+
+ .trigger-top {
+ display: flex;
+ align-items: center;
+ margin-bottom: 0.5rem;
+ padding-left: 7px;
+
+ .fill-space {
+ flex: 1;
+ }
+ }
+
+ .icon {
+ margin-right: 1rem;
+ color: $primary-color;
+ }
+
+ .fill-space {
+ flex: 1;
+ }
+
+ .flow-action-wrapper {
+ padding: 0 0.5rem;
+ margin: 0;
+
+ .flow-action {
+ display: flex;
+ align-items: center;
+ font-size: 14px;
+ padding: 0.5rem 0;
+ cursor: move;
+
+ .flow-action-name {
+ margin-right: 1rem;
+ }
+
+ .fill-space {
+ flex: 1;
+ }
+
+ i {
+ margin-right: 0.5rem;
+ }
+ }
+
+ .state {
+ margin-left: 1rem;
+ }
+ }
+ }
+ }
+
+ .actions-topbottomline {
+ position: absolute;
+ top: 26px;
+ bottom: 1.5rem;
+ left: 35px;
+ width: 2px;
+ z-index: 0;
+ background-color: $primary-color;
+ }
+
+ .add-btn {
+ display: flex;
+ align-items: center;
+ align-self: flex-start;
+ margin: 1rem 0;
+ }
+ }
+
+ .cdk-drag-preview {
+ color: white;
+ display: flex;
+ align-items: center;
+ font-size: 14px;
+ border-radius: 0.5rem;
+ padding: 0 0.5rem;
+ background-color: $primary-color;
+ box-shadow:
+ 0 5px 5px -3px rgba(0, 0, 0, 0.2),
+ 0 8px 10px 1px rgba(0, 0, 0, 0.14),
+ 0 3px 14px 2px rgba(0, 0, 0, 0.12);
+
+ i {
+ margin-right: 0.5rem;
+ }
+ }
+
+ .cdk-drag-placeholder {
+ opacity: 0;
+ }
+
+ .cdk-drag-animating {
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+ }
+ }
+}
diff --git a/console/src/app/pages/org-actions/actions.component.spec.ts b/console/src/app/pages/org-actions/actions.component.spec.ts
new file mode 100644
index 0000000000..5b4d68e7de
--- /dev/null
+++ b/console/src/app/pages/org-actions/actions.component.spec.ts
@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ActionsComponent } from './actions.component';
+
+describe('ActionsComponent', () => {
+ let component: ActionsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ActionsComponent],
+ }).compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ActionsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/console/src/app/pages/org-actions/actions.component.ts b/console/src/app/pages/org-actions/actions.component.ts
new file mode 100644
index 0000000000..f926e7b819
--- /dev/null
+++ b/console/src/app/pages/org-actions/actions.component.ts
@@ -0,0 +1,180 @@
+import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
+import { Component, DestroyRef } from '@angular/core';
+import { UntypedFormControl } from '@angular/forms';
+import { MatDialog } from '@angular/material/dialog';
+import { ActionKeysType } from 'src/app/modules/action-keys/action-keys.component';
+import { InfoSectionType } from 'src/app/modules/info-section/info-section.component';
+import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
+import { Action, ActionState, Flow, FlowType, TriggerType } from 'src/app/proto/generated/zitadel/action_pb';
+import { SetTriggerActionsRequest } from 'src/app/proto/generated/zitadel/management_pb';
+import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
+import { ManagementService } from 'src/app/services/mgmt.service';
+import { ToastService } from 'src/app/services/toast.service';
+
+import { AddFlowDialogComponent } from './add-flow-dialog/add-flow-dialog.component';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+
+@Component({
+ selector: 'cnsl-actions',
+ templateUrl: './actions.component.html',
+ styleUrls: ['./actions.component.scss'],
+})
+export class ActionsComponent {
+ protected flow!: Flow.AsObject;
+
+ protected typeControl: UntypedFormControl = new UntypedFormControl();
+
+ protected typesForSelection: FlowType.AsObject[] = [];
+
+ protected selection: Action.AsObject[] = [];
+ protected InfoSectionType = InfoSectionType;
+ protected ActionKeysType = ActionKeysType;
+
+ protected maxActions: number | null = null;
+ protected ActionState = ActionState;
+ constructor(
+ private mgmtService: ManagementService,
+ breadcrumbService: BreadcrumbService,
+ private dialog: MatDialog,
+ private toast: ToastService,
+ destroyRef: DestroyRef,
+ ) {
+ const bread: Breadcrumb = {
+ type: BreadcrumbType.ORG,
+ routerLink: ['/org'],
+ };
+ breadcrumbService.setBreadcrumb([bread]);
+
+ this.getFlowTypes().then();
+
+ this.typeControl.valueChanges.pipe(takeUntilDestroyed(destroyRef)).subscribe((value) => {
+ this.loadFlow((value as FlowType.AsObject).id);
+ });
+ }
+
+ private async getFlowTypes(): Promise {
+ try {
+ let resp = await this.mgmtService.listFlowTypes();
+ this.typesForSelection = resp.resultList;
+ if (!this.flow && resp.resultList[0]) {
+ const type = resp.resultList[0];
+ this.typeControl.setValue(type);
+ }
+ } catch (error) {
+ this.toast.showError(error);
+ }
+ }
+
+ private loadFlow(id: string) {
+ this.mgmtService.getFlow(id).then((flowResponse) => {
+ if (flowResponse.flow) {
+ this.flow = flowResponse.flow;
+ }
+ });
+ }
+
+ public clearFlow(id: string): void {
+ const dialogRef = this.dialog.open(WarnDialogComponent, {
+ data: {
+ confirmKey: 'ACTIONS.CLEAR',
+ cancelKey: 'ACTIONS.CANCEL',
+ titleKey: 'FLOWS.DIALOG.CLEAR.TITLE',
+ descriptionKey: 'FLOWS.DIALOG.CLEAR.DESCRIPTION',
+ },
+ width: '400px',
+ });
+
+ dialogRef.afterClosed().subscribe((resp) => {
+ if (resp) {
+ this.mgmtService
+ .clearFlow(id)
+ .then(() => {
+ this.toast.showInfo('FLOWS.FLOWCLEARED', true);
+ this.loadFlow(id);
+ })
+ .catch((error: any) => {
+ this.toast.showError(error);
+ });
+ }
+ });
+ }
+
+ protected openAddTrigger(flow: FlowType.AsObject, trigger?: TriggerType.AsObject): void {
+ const dialogRef = this.dialog.open(AddFlowDialogComponent, {
+ data: {
+ flowType: flow,
+ actions: this.selection && this.selection.length ? this.selection : [],
+ },
+ width: '400px',
+ });
+
+ dialogRef.afterClosed().subscribe((req: SetTriggerActionsRequest) => {
+ if (req) {
+ this.mgmtService
+ .setTriggerActions(req.getActionIdsList(), req.getFlowType(), req.getTriggerType())
+ .then(() => {
+ this.toast.showInfo('FLOWS.FLOWCHANGED', true);
+ this.loadFlow(flow.id);
+ })
+ .catch((error: any) => {
+ this.toast.showError(error);
+ });
+ }
+ });
+ }
+
+ drop(triggerActionsListIndex: number, array: any[], event: CdkDragDrop) {
+ moveItemInArray(array, event.previousIndex, event.currentIndex);
+ this.saveFlow(triggerActionsListIndex);
+ }
+
+ saveFlow(index: number) {
+ if (
+ this.flow.type &&
+ this.flow.triggerActionsList &&
+ this.flow.triggerActionsList[index] &&
+ this.flow.triggerActionsList[index]?.triggerType
+ ) {
+ this.mgmtService
+ .setTriggerActions(
+ this.flow.triggerActionsList[index].actionsList.map((action) => action.id),
+ this.flow.type.id,
+ this.flow.triggerActionsList[index].triggerType?.id ?? '',
+ )
+ .then(() => {
+ this.toast.showInfo('FLOWS.TOAST.ACTIONSSET', true);
+ })
+ .catch((error) => {
+ this.toast.showError(error);
+ });
+ }
+ }
+
+ protected removeTriggerActionsList(index: number) {
+ if (this.flow.type && this.flow.triggerActionsList && this.flow.triggerActionsList[index]) {
+ const dialogRef = this.dialog.open(WarnDialogComponent, {
+ data: {
+ confirmKey: 'ACTIONS.CLEAR',
+ cancelKey: 'ACTIONS.CANCEL',
+ titleKey: 'FLOWS.DIALOG.REMOVEACTIONSLIST.TITLE',
+ descriptionKey: 'FLOWS.DIALOG.REMOVEACTIONSLIST.DESCRIPTION',
+ },
+ width: '400px',
+ });
+
+ dialogRef.afterClosed().subscribe((resp) => {
+ if (resp) {
+ this.mgmtService
+ .setTriggerActions([], this.flow?.type?.id ?? '', this.flow.triggerActionsList[index].triggerType?.id ?? '')
+ .then(() => {
+ this.toast.showInfo('FLOWS.TOAST.ACTIONSSET', true);
+ this.loadFlow(this.flow?.type?.id ?? '');
+ })
+ .catch((error) => {
+ this.toast.showError(error);
+ });
+ }
+ });
+ }
+ }
+}
diff --git a/console/src/app/pages/org-actions/actions.module.ts b/console/src/app/pages/org-actions/actions.module.ts
new file mode 100644
index 0000000000..c5da8663fa
--- /dev/null
+++ b/console/src/app/pages/org-actions/actions.module.ts
@@ -0,0 +1,68 @@
+import { DragDropModule } from '@angular/cdk/drag-drop';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatDialogModule } from '@angular/material/dialog';
+import { MatIconModule } from '@angular/material/icon';
+import { MatSelectModule } from '@angular/material/select';
+import { MatTableModule } from '@angular/material/table';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { CodemirrorModule } from '@ctrl/ngx-codemirror';
+import { TranslateModule } from '@ngx-translate/core';
+import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
+import { ActionKeysModule } from 'src/app/modules/action-keys/action-keys.module';
+import { CardModule } from 'src/app/modules/card/card.module';
+import { FormFieldModule } from 'src/app/modules/form-field/form-field.module';
+import { InfoSectionModule } from 'src/app/modules/info-section/info-section.module';
+import { InputModule } from 'src/app/modules/input/input.module';
+import { PaginatorModule } from 'src/app/modules/paginator/paginator.module';
+import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
+import { TableActionsModule } from 'src/app/modules/table-actions/table-actions.module';
+import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module';
+import { DurationToSecondsPipeModule } from 'src/app/pipes/duration-to-seconds-pipe/duration-to-seconds-pipe.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 { ActionTableComponent } from './action-table/action-table.component';
+import { ActionsRoutingModule } from './actions-routing.module';
+import { ActionsComponent } from './actions.component';
+import { AddActionDialogComponent } from './add-action-dialog/add-action-dialog.component';
+import { AddFlowDialogComponent } from './add-flow-dialog/add-flow-dialog.component';
+
+@NgModule({
+ declarations: [ActionsComponent, ActionTableComponent, AddActionDialogComponent, AddFlowDialogComponent],
+ imports: [
+ CommonModule,
+ FormsModule,
+ ActionsRoutingModule,
+ TranslateModule,
+ MatDialogModule,
+ RefreshTableModule,
+ MatTableModule,
+ PaginatorModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ MatIconModule,
+ DurationToSecondsPipeModule,
+ TimestampToDatePipeModule,
+ LocalizedDatePipeModule,
+ HasRoleModule,
+ ActionKeysModule,
+ MatTooltipModule,
+ CardModule,
+ MatCheckboxModule,
+ InputModule,
+ FormFieldModule,
+ MatSelectModule,
+ WarnDialogModule,
+ DragDropModule,
+ InfoSectionModule,
+ HasRolePipeModule,
+ TableActionsModule,
+ CodemirrorModule,
+ ],
+})
+export default class ActionsModule {}
diff --git a/console/src/app/pages/actions/add-action-dialog/add-action-dialog.component.html b/console/src/app/pages/org-actions/add-action-dialog/add-action-dialog.component.html
similarity index 100%
rename from console/src/app/pages/actions/add-action-dialog/add-action-dialog.component.html
rename to console/src/app/pages/org-actions/add-action-dialog/add-action-dialog.component.html
diff --git a/console/src/app/pages/actions/add-action-dialog/add-action-dialog.component.scss b/console/src/app/pages/org-actions/add-action-dialog/add-action-dialog.component.scss
similarity index 100%
rename from console/src/app/pages/actions/add-action-dialog/add-action-dialog.component.scss
rename to console/src/app/pages/org-actions/add-action-dialog/add-action-dialog.component.scss
diff --git a/console/src/app/pages/actions/add-action-dialog/add-action-dialog.component.spec.ts b/console/src/app/pages/org-actions/add-action-dialog/add-action-dialog.component.spec.ts
similarity index 100%
rename from console/src/app/pages/actions/add-action-dialog/add-action-dialog.component.spec.ts
rename to console/src/app/pages/org-actions/add-action-dialog/add-action-dialog.component.spec.ts
diff --git a/console/src/app/pages/actions/add-action-dialog/add-action-dialog.component.ts b/console/src/app/pages/org-actions/add-action-dialog/add-action-dialog.component.ts
similarity index 100%
rename from console/src/app/pages/actions/add-action-dialog/add-action-dialog.component.ts
rename to console/src/app/pages/org-actions/add-action-dialog/add-action-dialog.component.ts
diff --git a/console/src/app/pages/actions/add-flow-dialog/add-flow-dialog.component.html b/console/src/app/pages/org-actions/add-flow-dialog/add-flow-dialog.component.html
similarity index 100%
rename from console/src/app/pages/actions/add-flow-dialog/add-flow-dialog.component.html
rename to console/src/app/pages/org-actions/add-flow-dialog/add-flow-dialog.component.html
diff --git a/console/src/app/pages/actions/add-flow-dialog/add-flow-dialog.component.scss b/console/src/app/pages/org-actions/add-flow-dialog/add-flow-dialog.component.scss
similarity index 100%
rename from console/src/app/pages/actions/add-flow-dialog/add-flow-dialog.component.scss
rename to console/src/app/pages/org-actions/add-flow-dialog/add-flow-dialog.component.scss
diff --git a/console/src/app/pages/actions/add-flow-dialog/add-flow-dialog.component.spec.ts b/console/src/app/pages/org-actions/add-flow-dialog/add-flow-dialog.component.spec.ts
similarity index 100%
rename from console/src/app/pages/actions/add-flow-dialog/add-flow-dialog.component.spec.ts
rename to console/src/app/pages/org-actions/add-flow-dialog/add-flow-dialog.component.spec.ts
diff --git a/console/src/app/pages/actions/add-flow-dialog/add-flow-dialog.component.ts b/console/src/app/pages/org-actions/add-flow-dialog/add-flow-dialog.component.ts
similarity index 100%
rename from console/src/app/pages/actions/add-flow-dialog/add-flow-dialog.component.ts
rename to console/src/app/pages/org-actions/add-flow-dialog/add-flow-dialog.component.ts
diff --git a/console/src/component-themes.scss b/console/src/component-themes.scss
index f2bf03bd05..ef769438f9 100644
--- a/console/src/component-themes.scss
+++ b/console/src/component-themes.scss
@@ -37,7 +37,7 @@
@import 'src/app/pages/users/user-list/user-table/user-table.component';
@import 'src/app/pages/users/user-detail/contact/contact.component';
@import 'src/app/pages/projects/project-grid/project-grid.component';
-@import 'src/app/pages/actions/actions.component';
+@import 'src/app/pages/org-actions/actions.component';
@import 'src/app/app.component.scss';
@import './styles/color.scss';
@import 'src/app/pages/instance/instance.component.scss';