From c66c8506458c8157f4babe2e1b2e1b803b0f2ad7 Mon Sep 17 00:00:00 2001
From: Homada Boumedane <homada.boumedane@unige.ch>
Date: Wed, 4 Sep 2019 14:37:13 +0200
Subject: [PATCH] chore(dlcm-portal): translations

add translations for new menu

feat(dlcm-portal): OAuth2 Client

create OAuth2 client admin menu
---
 .../features/admin/admin-routing.module.ts    | 27 ++++--
 src/app/features/admin/admin.module.ts        | 22 +++--
 ...-funding-agencies-form.presentational.html | 89 +++++++++++++++++++
 ...in-funding-agencies-form.presentational.ts | 52 +++++++++++
 ...dmin-funding-agencies-detail.routable.html | 26 ++++++
 .../admin-funding-agencies-detail.routable.ts | 32 +++++++
 ...unding-agencies-list-routable.component.ts | 47 ++++++++++
 .../admin-home/admin-home.routable.ts         |  7 ++
 src/app/features/admin/stores/admin.state.ts  | 42 +++------
 .../admin-funding-agencies.action.ts          | 85 ++++++++++++++++++
 .../admin-funding-agencies.state.ts           | 40 +++++++++
 src/app/shared/enums/local-state.enum.ts      |  1 +
 src/app/shared/enums/routes.enum.ts           |  9 ++
 src/assets/i18n/de.json                       | 48 ++++++++++
 src/assets/i18n/en.json                       | 47 ++++++++++
 src/assets/i18n/fr.json                       | 47 ++++++++++
 16 files changed, 578 insertions(+), 43 deletions(-)
 create mode 100644 src/app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational.html
 create mode 100644 src/app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational.ts
 create mode 100644 src/app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable.html
 create mode 100644 src/app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable.ts
 create mode 100644 src/app/features/admin/components/routables/admin-funding-agencies-list/admin-funding-agencies-list-routable.component.ts
 create mode 100644 src/app/features/admin/stores/funding-agency/admin-funding-agencies.action.ts
 create mode 100644 src/app/features/admin/stores/funding-agency/admin-funding-agencies.state.ts

diff --git a/src/app/features/admin/admin-routing.module.ts b/src/app/features/admin/admin-routing.module.ts
index f9a3719dc..a5603e846 100644
--- a/src/app/features/admin/admin-routing.module.ts
+++ b/src/app/features/admin/admin-routing.module.ts
@@ -1,8 +1,5 @@
 import {NgModule} from "@angular/core";
-import {
-  RouterModule,
-  Routes,
-} from "@angular/router";
+import {RouterModule, Routes} from "@angular/router";
 import {AdminHomeRoutable} from "@app/features/admin/components/routables/admin-home/admin-home.routable";
 import {AdminInstitutionCreateRoutable} from "@app/features/admin/components/routables/admin-institution-create/admin-institution-create.routable";
 import {AdminInstitutionDetailRoutable} from "@app/features/admin/components/routables/admin-institution-detail/admin-institution-detail.routable";
@@ -41,12 +38,12 @@ import {AdminUserDetailRoutable} from "@app/features/admin/components/routables/
 import {AdminUserEditRoutable} from "@app/features/admin/components/routables/admin-user-edit/admin-user-edit.routable";
 import {AdminUserListRoutable} from "@app/features/admin/components/routables/admin-user-list/admin-user-list-routable";
 import {ApplicationRolePermissionEnum} from "@app/shared/enums/application-role-permission.enum";
-import {
-  AdminRoutesEnum,
-  AppRoutesEnum,
-} from "@app/shared/enums/routes.enum";
+import {AdminRoutesEnum, AppRoutesEnum} from "@app/shared/enums/routes.enum";
 import {ApplicationRoleGuardService} from "@app/shared/guards/application-role-guard.service";
 import {TRANSLATE} from "solidify-frontend";
+import {AdminFundingAgenciesListRoutable} from "@app/features/admin/components/routables/admin-funding-agencies-list/admin-funding-agencies-list-routable.component";
+import {AdminFundingAgenciesDetailRoutable} from "@app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable";
+
 
 const routes: Routes = [
   {
@@ -312,6 +309,20 @@ const routes: Routes = [
       breadcrumb: TRANSLATE("breadcrumb.admin.role.edit"),
     },
   },
+  {
+    path: AdminRoutesEnum.fundingAgencies,
+    component: AdminFundingAgenciesListRoutable,
+    data: {
+      breadcrumb: TRANSLATE("breadcrumb.admin.funding-agencies.list"),
+    },
+  },
+  {
+    path: AdminRoutesEnum.fundingAgencies + AppRoutesEnum.separator + AdminRoutesEnum.fundingAgenciesDetail + AppRoutesEnum.separator + AppRoutesEnum.paramId,
+    component: AdminFundingAgenciesDetailRoutable,
+    data: {
+      breadcrumb: TRANSLATE("breadcrumb.admin.funding-agencies.detail"),
+    },
+  },
 ];
 
 @NgModule({
diff --git a/src/app/features/admin/admin.module.ts b/src/app/features/admin/admin.module.ts
index 26ea9a8fe..de788cb72 100644
--- a/src/app/features/admin/admin.module.ts
+++ b/src/app/features/admin/admin.module.ts
@@ -2,20 +2,14 @@ import {NgModule} from "@angular/core";
 import {AdminRoutingModule} from "@app/features/admin/admin-routing.module";
 import {AdminInstitutionDeleteDialog} from "@app/features/admin/components/dialogs/admin-institution-delete/admin-institution-delete.dialog";
 import {AdminLicenseDeleteDialog} from "@app/features/admin/components/dialogs/admin-license-delete/admin-license-delete.dialog";
-import {AdminOauth2ClientDeleteDialog} from "@app/features/admin/components/dialogs/admin-oauth2-client-delete/admin-oauth2-client-delete.dialog";
 import {AdminOrgunitDeleteDialog} from "@app/features/admin/components/dialogs/admin-orgunit-delete/admin-orgunit-delete.dialog";
-import {AdminPersonDeleteDialog} from "@app/features/admin/components/dialogs/admin-person-delete/admin-person-delete.dialog";
 import {AdminPreservationPolicyDeleteDialog} from "@app/features/admin/components/dialogs/admin-preservation-policy-delete/admin-preservation-policy-delete.dialog";
-import {AdminRoleDeleteDialog} from "@app/features/admin/components/dialogs/admin-role-delete/admin-role-delete.dialog";
 import {AdminSubmissionPolicyDeleteDialog} from "@app/features/admin/components/dialogs/admin-submission-policy-delete/admin-submission-policy-delete.dialog";
 import {AdminUserDeleteDialog} from "@app/features/admin/components/dialogs/admin-user-delete/admin-user-delete.dialog";
 import {AdminInstitutionFormPresentational} from "@app/features/admin/components/presentationals/admin-institution-form/admin-institution-form.presentational";
 import {AdminLicenseFormPresentational} from "@app/features/admin/components/presentationals/admin-license-form/admin-license-form.presentational";
-import {AdminOAtuh2ClientFormPresentational} from "@app/features/admin/components/presentationals/admin-oauth2-client-form/admin-oauth2-client-form.presentational";
 import {AdminOrgunitFormPresentational} from "@app/features/admin/components/presentationals/admin-orgunit-form/admin-orgunit-form.presentational";
-import {AdminPersonForm} from "@app/features/admin/components/presentationals/admin-person-form/admin-person-form";
 import {AdminPreservationPolicyFormPresentational} from "@app/features/admin/components/presentationals/admin-preservation-policy-form/admin-preservation-policy-form.presentational";
-import {AdminRoleFormPresentational} from "@app/features/admin/components/presentationals/admin-role-form/admin-role-form.presentational";
 import {AdminSubmissionPolicyFormPresentational} from "@app/features/admin/components/presentationals/admin-submission-policy-form/admin-submission-policy-form.presentational";
 import {AdminUserForm} from "@app/features/admin/components/presentationals/admin-user-form/admin-user-form";
 import {AdminHomeRoutable} from "@app/features/admin/components/routables/admin-home/admin-home.routable";
@@ -70,6 +64,16 @@ import {SharedModule} from "@app/shared/shared.module";
 import {TranslateModule} from "@ngx-translate/core";
 import {NgxsModule} from "@ngxs/store";
 import {AdminSubmissionPolicyListRoutable} from "./components/routables/admin-submission-policy-list/admin-submission-policy-list.routable";
+import {AdminOauth2ClientDeleteDialog} from "@app/features/admin/components/dialogs/admin-oauth2-client-delete/admin-oauth2-client-delete.dialog";
+import {AdminOAtuh2ClientFormPresentational} from "@app/features/admin/components/presentationals/admin-oauth2-client-form/admin-oauth2-client-form.presentational";
+import {AdminPersonForm} from "@app/features/admin/components/presentationals/admin-person-form/admin-person-form";
+import {AdminPersonDeleteDialog} from "@app/features/admin/components/dialogs/admin-person-delete/admin-person-delete.dialog";
+import {AdminRoleFormPresentational} from "@app/features/admin/components/presentationals/admin-role-form/admin-role-form.presentational";
+import {AdminRoleDeleteDialog} from "@app/features/admin/components/dialogs/admin-role-delete/admin-role-delete.dialog";
+import {AdminFundingAgenciesListRoutable} from "@app/features/admin/components/routables/admin-funding-agencies-list/admin-funding-agencies-list-routable.component";
+import {AdminFundingAgenciesState} from "@app/features/admin/stores/funding-agency/admin-funding-agencies.state";
+import {AdminFundingAgenciesDetailRoutable} from "@app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable";
+import {AdminFundingAgenciesFormPresentational} from "@app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational";
 
 const routables = [
   AdminHomeRoutable,
@@ -109,6 +113,8 @@ const routables = [
   AdminRoleCreateRoutable,
   AdminRoleDetailRoutable,
   AdminRoleEditRoutable,
+  AdminFundingAgenciesListRoutable,
+  AdminFundingAgenciesDetailRoutable
 ];
 const containers = [];
 const dialogs = [
@@ -120,7 +126,7 @@ const dialogs = [
   AdminUserDeleteDialog,
   AdminOauth2ClientDeleteDialog,
   AdminPersonDeleteDialog,
-  AdminRoleDeleteDialog,
+  AdminRoleDeleteDialog
 ];
 const presentationals = [
   AdminSubmissionPolicyFormPresentational,
@@ -132,6 +138,7 @@ const presentationals = [
   AdminOAtuh2ClientFormPresentational,
   AdminPersonForm,
   AdminRoleFormPresentational,
+  AdminFundingAgenciesFormPresentational
 ];
 
 @NgModule({
@@ -158,6 +165,7 @@ const presentationals = [
       AdminOAuth2ClientState,
       AdminPersonState,
       AdminRoleState,
+      AdminFundingAgenciesState
     ]),
   ],
   entryComponents: [
diff --git a/src/app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational.html b/src/app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational.html
new file mode 100644
index 000000000..a80ebbea5
--- /dev/null
+++ b/src/app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational.html
@@ -0,0 +1,89 @@
+<form [formGroup]="form"
+      (ngSubmit)="onSubmit()">
+  <mat-form-field>
+    <mat-label>{{'admin.license.form.title' | translate}}</mat-label>
+    <input matInput
+           [formControlName]="formDefinition.title"
+           [required]="isRequired(formDefinition.title)">
+    <mat-error *ngIf="getFormControl(formDefinition.title).invalid">{{'required' | translate}}</mat-error>
+    <mat-error *ngFor="let error of getFormControl(formDefinition.title).errors?.errorsFromBackend">{{error}}</mat-error>
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>{{'admin.license.form.openLicenseId' | translate}}</mat-label>
+    <input matInput
+           [formControlName]="formDefinition.openLicenseId"
+           [required]="isRequired(formDefinition.openLicenseId)">
+    <mat-error *ngIf="getFormControl(formDefinition.openLicenseId).invalid">{{'required' | translate}}</mat-error>
+    <mat-error *ngFor="let error of getFormControl(formDefinition.openLicenseId).errors?.errorsFromBackend">{{error}}</mat-error>
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>{{'admin.license.form.url' | translate}}</mat-label>
+    <input matInput
+           [formControlName]="formDefinition.url">
+    <mat-error *ngFor="let error of getFormControl(formDefinition.url).errors?.errorsFromBackend">{{error}}</mat-error>
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>{{'admin.license.form.maintainer' | translate}}</mat-label>
+    <input matInput
+           [formControlName]="formDefinition.maintainer">
+    <mat-error *ngFor="let error of getFormControl(formDefinition.maintainer).errors?.errorsFromBackend">{{error}}</mat-error>
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>{{'admin.license.form.odConformance' | translate}}</mat-label>
+    <mat-select [formControlName]="formDefinition.odConformance">
+      <mat-option *ngFor="let odConformance of licenseOdConformanceEnum" [value]="odConformance">
+        {{odConformance}}
+      </mat-option>
+    </mat-select>
+    <mat-error *ngFor="let error of getFormControl(formDefinition.odConformance).errors?.errorsFromBackend">{{error}}</mat-error>
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>{{'admin.license.form.osdConformance' | translate}}</mat-label>
+    <mat-select [formControlName]="formDefinition.osdConformance">
+      <mat-option *ngFor="let osdConformance of licenseOsdConformanceEnum" [value]="osdConformance">
+        {{osdConformance}}
+      </mat-option>
+    </mat-select>
+    <mat-error *ngFor="let error of getFormControl(formDefinition.osdConformance).errors?.errorsFromBackend">{{error}}</mat-error>
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>{{'admin.license.form.status' | translate}}</mat-label>
+    <mat-select [formControlName]="formDefinition.status">
+      <mat-option *ngFor="let status of licensesStatusEnum" [value]="status">
+        {{status}}
+      </mat-option>
+    </mat-select>
+    <mat-error *ngFor="let error of getFormControl(formDefinition.status).errors?.errorsFromBackend">{{error}}</mat-error>
+  </mat-form-field>
+
+  <mat-checkbox [formControlName]="formDefinition.isGeneric">{{'admin.license.form.isGeneric' | translate }}</mat-checkbox>
+
+  <mat-form-field>
+    <mat-label>{{'admin.license.form.family' | translate}}</mat-label>
+    <input matInput
+           [formControlName]="formDefinition.family">
+    <mat-error *ngFor="let error of getFormControl(formDefinition.family).errors?.errorsFromBackend">{{error}}</mat-error>
+  </mat-form-field>
+
+  <mat-checkbox [formControlName]="formDefinition.domainContent">{{'admin.license.form.domainContent' | translate }}</mat-checkbox>
+
+  <mat-checkbox [formControlName]="formDefinition.domainData">{{'admin.license.form.domainData' | translate }}</mat-checkbox>
+
+  <mat-checkbox [formControlName]="formDefinition.domainSoftware">{{'admin.license.form.domainSoftware' | translate }}</mat-checkbox>
+
+  <div class="submit-button">
+    <button *ngIf="!readonly"
+            mat-flat-button
+            color="primary"
+            type="submit"
+            [disabled]="!form.valid">
+      {{'admin.license.form.submit' | translate }}
+    </button>
+  </div>
+</form>
diff --git a/src/app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational.ts b/src/app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational.ts
new file mode 100644
index 000000000..b29eecb82
--- /dev/null
+++ b/src/app/features/admin/components/presentationals/admin-funding-agencies-form/admin-funding-agencies-form.presentational.ts
@@ -0,0 +1,52 @@
+import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from "@angular/core";
+import {FormBuilder, Validators} from "@angular/forms";
+import {FundingAgency, License} from "@app/generated-api";
+import {SharedAbstractFormPresentational} from "@app/shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational";
+import {odConformanceEnum, osdConformanceEnum} from "@app/shared/enums/license.enums";
+import {BaseFormDefinition} from "@app/shared/models/base-form-definition.model";
+import {PropertyName, SolidifyValidator} from "solidify-frontend";
+
+@Component({
+  selector: "dlcm-admin-funding-agencies-form",
+  templateUrl: "./admin-funding-agencies-form.presentational.html",
+  styleUrls: ["../../../../../shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational.scss"],
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AdminFundingAgenciesFormPresentational extends SharedAbstractFormPresentational<FundingAgency> {
+  formDefinition: FormComponentFormDefinition = new FormComponentFormDefinition();
+
+  constructor(protected readonly _changeDetectorRef: ChangeDetectorRef,
+              private readonly _fb: FormBuilder) {
+    super(_changeDetectorRef);
+  }
+
+  protected initNewForm(): void {
+    this.form = this._fb.group({
+      [this.formDefinition.acronym]: ["", [Validators.required, SolidifyValidator]],
+      [this.formDefinition.name]: ["", [Validators.required, SolidifyValidator]],
+      [this.formDefinition.description]: ["", [SolidifyValidator]],
+      [this.formDefinition.url]: ["", [SolidifyValidator]],
+    });
+  }
+
+  protected bindFormTo(fundingAgency: FundingAgency): void {
+    this.form = this._fb.group({
+      [this.formDefinition.acronym]: [fundingAgency.acronym, [Validators.required, SolidifyValidator]],
+      [this.formDefinition.name]: [fundingAgency.name, [Validators.required, SolidifyValidator]],
+      [this.formDefinition.description]: [fundingAgency.description, [SolidifyValidator]],
+      [this.formDefinition.url]: [fundingAgency.url, [SolidifyValidator]],
+    });
+  }
+
+  protected treatmentBeforeSubmit(licenses: License): License {
+    return licenses;
+  }
+
+}
+
+class FormComponentFormDefinition extends BaseFormDefinition {
+  @PropertyName() acronym: string;
+  @PropertyName() name: string;
+  @PropertyName() description: string;
+  @PropertyName() url: string;
+}
diff --git a/src/app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable.html b/src/app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable.html
new file mode 100644
index 000000000..f0a0ddfd8
--- /dev/null
+++ b/src/app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable.html
@@ -0,0 +1,26 @@
+<div class="button-toolbar">
+  <button mat-flat-button
+          color="primary"
+          (click)="edit()">
+    {{KEY_EDIT_BUTTON | translate}}
+  </button>
+  <button mat-flat-button
+          color="accent"
+          [disabled]="!(currentObs| async)"
+          (click)="delete()">
+    {{KEY_DELETE_BUTTON | translate}}
+  </button>
+</div>
+
+<div class="wrapper">
+  <div class="spinner-wrapper" *ngIf="isLoadingObs | async">
+    <mat-spinner></mat-spinner>
+  </div>
+
+  <dlcm-admin-oauth-form *ngIf="(currentObs| async) != null"
+                         [model]="currentObs| async"
+                         [readonly]="true">
+
+  </dlcm-admin-oauth-form>
+
+</div>
diff --git a/src/app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable.ts b/src/app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable.ts
new file mode 100644
index 000000000..c957f83af
--- /dev/null
+++ b/src/app/features/admin/components/routables/admin-funding-agencies-detail/admin-funding-agencies-detail.routable.ts
@@ -0,0 +1,32 @@
+import {ChangeDetectionStrategy, Component} from "@angular/core";
+import {MatDialog} from "@angular/material";
+import {ActivatedRoute} from "@angular/router";
+import {FundingAgency} from "@app/generated-api";
+import {SharedAbstractDetailRoutable} from "@app/shared/components/routables/shared-abstract-detail/shared-abstract-detail.routable";
+import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
+import {Store} from "@ngxs/store";
+import {TRANSLATE} from "solidify-frontend";
+import {AdminFundingAgenciesStateModel} from "@app/features/admin/stores/funding-agency/admin-funding-agencies.state";
+import {adminFundingAgenciesActionNameSpace} from "@app/features/admin/stores/funding-agency/admin-funding-agencies.action";
+
+@Component({
+  selector: "dlcm-admin-oauth2-client-detail-routable",
+  templateUrl: "./admin-oauth2-client-detail.routable.html",
+  styleUrls: ["../../../../../shared/components/routables/shared-abstract-detail/shared-abstract-detail.routable.scss"],
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AdminFundingAgenciesDetailRoutable extends SharedAbstractDetailRoutable<FundingAgency, AdminFundingAgenciesStateModel> {
+  readonly KEY_PARAM_NAME: string = "name";
+  readonly KEY_DELETE_BUTTON: string = TRANSLATE("admin.funding-agencies.button.delete");
+  readonly KEY_EDIT_BUTTON: string = TRANSLATE("admin.funding-agencies.button.edit");
+
+  constructor(protected store: Store,
+              protected route: ActivatedRoute,
+              public dialog: MatDialog) {
+    super(store, route, dialog, LocalStateEnum.admin_fundingAgencies, adminFundingAgenciesActionNameSpace, LocalStateEnum.admin);
+  }
+
+  getSubResourceWithParentId(id: string): void {
+  }
+
+}
diff --git a/src/app/features/admin/components/routables/admin-funding-agencies-list/admin-funding-agencies-list-routable.component.ts b/src/app/features/admin/components/routables/admin-funding-agencies-list/admin-funding-agencies-list-routable.component.ts
new file mode 100644
index 000000000..81afd47b1
--- /dev/null
+++ b/src/app/features/admin/components/routables/admin-funding-agencies-list/admin-funding-agencies-list-routable.component.ts
@@ -0,0 +1,47 @@
+import {ChangeDetectionStrategy, Component} from "@angular/core";
+import {adminOAuth2ClientActionNameSpace} from "@app/features/admin/stores/oauth2-client/admin-oauth2-client.action";
+import {AdminOAuth2ClientStateModel} from "@app/features/admin/stores/oauth2-client/admin-oauth2-client.state";
+import {FundingAgency, Oauth2Client} from "@app/generated-api";
+import {SharedAbstractListRoutable} from "@app/shared/components/routables/shared-abstract-list/shared-abstract-list.routable";
+import {FieldTypeEnum} from "@app/shared/enums/field-type.enum";
+import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
+import {Store} from "@ngxs/store";
+import {TRANSLATE} from "solidify-frontend";
+import {AdminFundingAgenciesStateModel} from "@app/features/admin/stores/funding-agency/admin-funding-agencies.state";
+import {adminFundingAgenciesActionNameSpace} from "@app/features/admin/stores/funding-agency/admin-funding-agencies.action";
+
+@Component({
+  selector: "dlcm-admin-submission-policy-list-routable",
+  templateUrl: "../../../../../shared/components/routables/shared-abstract-list/shared-abstract-list.routable.html",
+  styleUrls: ["../../../../../shared/components/routables/shared-abstract-list/shared-abstract-list.routable.scss"],
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AdminFundingAgenciesListRoutable extends SharedAbstractListRoutable<FundingAgency, AdminFundingAgenciesStateModel> {
+  readonly KEY_CREATE_BUTTON: string = TRANSLATE("admin.funding-agencies.button.new");
+  readonly KEY_REFRESH_BUTTON: string = TRANSLATE("admin.funding-agencies.button.refresh");
+
+  constructor(protected store: Store) {
+    super(store, LocalStateEnum.admin_fundingAgencies, adminFundingAgenciesActionNameSpace, {}, LocalStateEnum.admin);
+  }
+
+  defineColumns(): void {
+    this.columns = [
+      {
+        field: "acronym",
+        header: TRANSLATE("admin.funding-agencies.table.header.acronym"),
+        type: FieldTypeEnum.string,
+        order: 0,
+        isFilterable: true,
+        isSortable: true,
+      },
+      {
+        field: "name",
+        header: TRANSLATE("admin.funding-agencies.table.header.name"),
+        type: FieldTypeEnum.string,
+        order: 0,
+        isFilterable: true,
+        isSortable: true,
+      }
+    ];
+  }
+}
diff --git a/src/app/features/admin/components/routables/admin-home/admin-home.routable.ts b/src/app/features/admin/components/routables/admin-home/admin-home.routable.ts
index fdc446db5..f376318fc 100644
--- a/src/app/features/admin/components/routables/admin-home/admin-home.routable.ts
+++ b/src/app/features/admin/components/routables/admin-home/admin-home.routable.ts
@@ -86,6 +86,13 @@ export class AdminHomeRoutable extends SharedAbstractPresentational {
       path: RoutesEnum.adminPerson,
       isVisible: () => true,
     },
+    {
+      avatarIcon: "hand-holding-usd",
+      titleToTranslate: TRANSLATE("admin.funding-agencies.home.title"),
+      subtitleToTranslate: TRANSLATE("admin.funding-agencies.home.subtitle"),
+      path: RoutesEnum.adminFundingAgencies,
+      isVisible: () => true,
+    }
   ];
 
   constructor(private store: Store) {
diff --git a/src/app/features/admin/stores/admin.state.ts b/src/app/features/admin/stores/admin.state.ts
index d4cc1f22b..dfbf6f9b2 100644
--- a/src/app/features/admin/stores/admin.state.ts
+++ b/src/app/features/admin/stores/admin.state.ts
@@ -1,45 +1,28 @@
-import {
-  AdminInstitutionState,
-  AdminInstitutionStateModel,
-} from "@app/features/admin/stores/institution/admin-institution.state";
-import {
-  AdminLicenseState,
-  AdminLicenseStateModel,
-} from "@app/features/admin/stores/license/admin-license.state";
-import {
-  AdminOAuth2ClientState,
-  AdminOAuth2ClientStateModel,
-} from "@app/features/admin/stores/oauth2-client/admin-oauth2-client.state";
+import {AdminInstitutionState, AdminInstitutionStateModel} from "@app/features/admin/stores/institution/admin-institution.state";
+import {AdminLicenseState, AdminLicenseStateModel} from "@app/features/admin/stores/license/admin-license.state";
+import {AdminOAuth2ClientState, AdminOAuth2ClientStateModel} from "@app/features/admin/stores/oauth2-client/admin-oauth2-client.state";
 import {
   AdminOrganizationalUnitState,
   AdminOrganizationalUnitStateModel,
 } from "@app/features/admin/stores/organizational-unit/admin-organizational-unit.state";
-import {
-  AdminPersonState,
-  AdminPersonStateModel,
-} from "@app/features/admin/stores/person/admin-person.state";
+import {AdminPersonState, AdminPersonStateModel} from "@app/features/admin/stores/person/admin-person.state";
 import {
   AdminPreservationPolicyState,
   AdminPreservationPolicyStateModel,
 } from "@app/features/admin/stores/preservation-policy/admin-preservation-policy.state";
-import {
-  AdminRoleState,
-  AdminRoleStateModel,
-} from "@app/features/admin/stores/role/admin-role.state";
 import {
   AdminSubmissionPolicyState,
   AdminSubmissionPolicyStateModel,
 } from "@app/features/admin/stores/submission-policy/admin-submission-policy.state";
-import {
-  AdminUserState,
-  AdminUserStateModel,
-} from "@app/features/admin/stores/user/admin-user.state";
+import {AdminUserState, AdminUserStateModel} from "@app/features/admin/stores/user/admin-user.state";
 import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
-import {
-  State,
-  Store,
-} from "@ngxs/store";
+import {State, Store} from "@ngxs/store";
 import {BaseStateModel} from "solidify-frontend";
+import {AdminRoleState, AdminRoleStateModel} from "@app/features/admin/stores/role/admin-role.state";
+import {
+  AdminFundingAgenciesState,
+  AdminFundingAgenciesStateModel
+} from "@app/features/admin/stores/funding-agency/admin-funding-agencies.state";
 
 export interface AdminStateModel extends BaseStateModel {
   admin_submissionPolicy: AdminSubmissionPolicyStateModel;
@@ -51,6 +34,7 @@ export interface AdminStateModel extends BaseStateModel {
   admin_oauth2Client: AdminOAuth2ClientStateModel;
   admin_person: AdminPersonStateModel;
   admin_role: AdminRoleStateModel;
+  admin_fundingAgencies: AdminFundingAgenciesStateModel;
 }
 
 @State<AdminStateModel>({
@@ -66,6 +50,7 @@ export interface AdminStateModel extends BaseStateModel {
     admin_oauth2Client: null,
     admin_person: null,
     admin_role: null,
+    admin_fundingAgencies: null,
   },
   children: [
     AdminSubmissionPolicyState,
@@ -77,6 +62,7 @@ export interface AdminStateModel extends BaseStateModel {
     AdminOAuth2ClientState,
     AdminPersonState,
     AdminRoleState,
+    AdminFundingAgenciesState
   ],
 })
 export class AdminState {
diff --git a/src/app/features/admin/stores/funding-agency/admin-funding-agencies.action.ts b/src/app/features/admin/stores/funding-agency/admin-funding-agencies.action.ts
new file mode 100644
index 000000000..4f36d2866
--- /dev/null
+++ b/src/app/features/admin/stores/funding-agency/admin-funding-agencies.action.ts
@@ -0,0 +1,85 @@
+import {FundingAgency} from "@app/generated-api";
+import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
+import {ResourceAction, ResourceNameSpace, TypeDefaultAction} from "solidify-frontend";
+
+const state = LocalStateEnum.admin_fundingAgencies;
+
+export namespace AdminFundingAgenciesAction {
+  @TypeDefaultAction(state)
+  export class LoadResource extends ResourceAction.LoadResource {
+  }
+
+  @TypeDefaultAction(state)
+  export class LoadResourceSuccess extends ResourceAction.LoadResourceSuccess {
+  }
+
+  @TypeDefaultAction(state)
+  export class LoadResourceFail extends ResourceAction.LoadResourceFail {
+  }
+
+  @TypeDefaultAction(state)
+  export class ChangeQueryParameters extends ResourceAction.ChangeQueryParameters {
+  }
+
+  @TypeDefaultAction(state)
+  export class GetAll extends ResourceAction.GetAll {
+  }
+
+  @TypeDefaultAction(state)
+  export class GetAllSuccess extends ResourceAction.GetAllSuccess<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class GetAllFail extends ResourceAction.GetAllFail<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class GetById extends ResourceAction.GetById {
+  }
+
+  @TypeDefaultAction(state)
+  export class GetByIdSuccess extends ResourceAction.GetByIdSuccess<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class GetByIdFail extends ResourceAction.GetByIdFail<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class Create extends ResourceAction.Create<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class CreateSuccess extends ResourceAction.CreateSuccess<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class CreateFail extends ResourceAction.CreateFail<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class Update extends ResourceAction.Update<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class UpdateSuccess extends ResourceAction.UpdateSuccess<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class UpdateFail extends ResourceAction.UpdateFail<FundingAgency> {
+  }
+
+  @TypeDefaultAction(state)
+  export class Delete extends ResourceAction.Delete {
+  }
+
+  @TypeDefaultAction(state)
+  export class DeleteSuccess extends ResourceAction.DeleteSuccess {
+  }
+
+  @TypeDefaultAction(state)
+  export class DeleteFail extends ResourceAction.DeleteFail {
+  }
+}
+
+export const adminFundingAgenciesActionNameSpace: ResourceNameSpace = AdminFundingAgenciesAction;
diff --git a/src/app/features/admin/stores/funding-agency/admin-funding-agencies.state.ts b/src/app/features/admin/stores/funding-agency/admin-funding-agencies.state.ts
new file mode 100644
index 000000000..c4260db05
--- /dev/null
+++ b/src/app/features/admin/stores/funding-agency/admin-funding-agencies.state.ts
@@ -0,0 +1,40 @@
+import {FundingAgency} from "@app/generated-api";
+import {AdminResourceApiEnum} from "@app/shared/enums/api.enum";
+import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
+import {RoutesEnum} from "@app/shared/enums/routes.enum";
+import {Actions, State, Store} from "@ngxs/store";
+import {
+  ApiService,
+  defaultResourceStateInitValue,
+  NotificationService,
+  ResourceState,
+  ResourceStateModel,
+  TRANSLATE,
+} from "solidify-frontend";
+import {adminFundingAgenciesActionNameSpace} from "@app/features/admin/stores/funding-agency/admin-funding-agencies.action";
+
+
+export interface AdminFundingAgenciesStateModel extends ResourceStateModel<FundingAgency> {
+}
+
+@State<AdminFundingAgenciesStateModel>({
+  name: LocalStateEnum.admin_fundingAgencies,
+  defaults: {
+    ...defaultResourceStateInitValue,
+  },
+})
+export class AdminFundingAgenciesState extends ResourceState<FundingAgency> {
+  constructor(protected apiService: ApiService,
+              protected store: Store,
+              protected notificationService: NotificationService,
+              protected actions$: Actions) {
+    super(apiService, store, notificationService, actions$, {
+      nameSpace: adminFundingAgenciesActionNameSpace,
+      urlResource: AdminResourceApiEnum.fundingAgencies,
+      routeRedirectUrlAfterSuccessAction: RoutesEnum.admin,
+      notificationResourceCreateTextToTranslate: TRANSLATE("admin.funding-agencies.notification.resource.create"),
+      notificationResourceDeleteTextToTranslate: TRANSLATE("admin.funding-agencies.notification.resource.delete"),
+      notificationResourceUpdateTextToTranslate: TRANSLATE("admin.funding-agencies.notification.resource.update"),
+    });
+  }
+}
diff --git a/src/app/shared/enums/local-state.enum.ts b/src/app/shared/enums/local-state.enum.ts
index b4a8c5a2a..5338b3f0d 100644
--- a/src/app/shared/enums/local-state.enum.ts
+++ b/src/app/shared/enums/local-state.enum.ts
@@ -35,4 +35,5 @@ export enum LocalStateEnum {
   admin_user = "admin_user",
   admin_person = "admin_person",
   admin_role = "admin_role",
+  admin_fundingAgencies = "admin_fundingAgencies",
 }
diff --git a/src/app/shared/enums/routes.enum.ts b/src/app/shared/enums/routes.enum.ts
index aae35c9a1..eca30ae89 100644
--- a/src/app/shared/enums/routes.enum.ts
+++ b/src/app/shared/enums/routes.enum.ts
@@ -66,6 +66,10 @@ export enum AdminRoutesEnum {
   roleDetail = "detail",
   roleCreate = "create",
   roleEdit = "edit",
+  fundingAgencies = "funding-agencies",
+  fundingAgenciesDetail = "detail",
+  fundingAgenciesCreate = "create",
+  fundingAgenciesEdit = "edit",
 }
 
 export class RoutesEnum implements RoutesEnum {
@@ -131,4 +135,9 @@ export class RoutesEnum implements RoutesEnum {
   static adminRoleCreate: string = AppRoutesEnum.admin + urlSeparator + AdminRoutesEnum.role + urlSeparator + AdminRoutesEnum.roleCreate;
   static adminRoleDetail: string = AppRoutesEnum.admin + urlSeparator + AdminRoutesEnum.role + urlSeparator + AdminRoutesEnum.roleDetail;
   static adminRoleEdit: string = AppRoutesEnum.admin + urlSeparator + AdminRoutesEnum.role + urlSeparator + AdminRoutesEnum.roleEdit;
+
+  static adminFundingAgencies: string = AppRoutesEnum.admin + urlSeparator + AdminRoutesEnum.fundingAgencies;
+  static adminFundingAgenciesCreate: string = AppRoutesEnum.admin + urlSeparator + AdminRoutesEnum.fundingAgencies + urlSeparator + AdminRoutesEnum.fundingAgenciesCreate;
+  static adminFundingAgenciesDetail: string = AppRoutesEnum.admin + urlSeparator + AdminRoutesEnum.fundingAgencies + urlSeparator + AdminRoutesEnum.fundingAgenciesDetail;
+  static adminFundingAgenciesEdit: string = AppRoutesEnum.admin + urlSeparator + AdminRoutesEnum.fundingAgencies + urlSeparator + AdminRoutesEnum.fundingAgenciesEdit;
 }
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index 4def43648..746c73751 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -422,6 +422,47 @@
           "update": "Role updated with success"
         }
       }
+    },
+    "funding-agencies": {
+      "button": {
+        "delete": "Delete",
+        "edit": "Edit",
+        "new": "Create Funding Agency",
+        "refresh": "Refresh"
+      },
+      "dialog": {
+        "delete": {
+          "cancel": "Cancel",
+          "confirm": "Yes",
+          "message": "Are you sure you want to delete the funding agency '{{name}}'?",
+          "title": "Confirm deletion"
+        }
+      },
+      "form": {
+        "acronym": "Acronym",
+        "name": "Name",
+        "description": "Description",
+        "url": "Url",
+        "organizational-units": "Organizational Units",
+        "submit": "Submit"
+      },
+      "home": {
+        "subtitle": "Describe funding agency",
+        "title": "Funding agency"
+      },
+      "notification": {
+        "resource": {
+          "create": "Funding agency created with success",
+          "delete": "Funding agency deleted with success",
+          "update": "Role updated with success"
+        }
+      },
+      "table": {
+        "header": {
+          "acronym": "Acronym",
+          "name": "Name"
+        }
+      }
     }
   },
   "app": {
@@ -495,6 +536,13 @@
         "edit": "Edit",
         "list": "List",
         "root": "Roles"
+      },
+      "funding-agencies": {
+        "create": "Create funding agency",
+        "detail": "Detail",
+        "edit": "Edit",
+        "list": "List",
+        "root": "Funding agencies"
       }
     },
     "deposit": {
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 4def43648..5ae22f020 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -422,6 +422,46 @@
           "update": "Role updated with success"
         }
       }
+    },
+    "funding-agencies": {
+      "button": {
+        "delete": "Delete",
+        "edit": "Edit",
+        "new": "Create Funding Agency",
+        "refresh": "Refresh"
+      },
+      "dialog": {
+        "delete": {
+          "cancel": "Cancel",
+          "confirm": "Yes",
+          "message": "Are you sure you want to delete the funding agency '{{name}}'?",
+          "title": "Confirm deletion"
+        }
+      },
+      "form": {
+        "acronym": "Acronym",
+        "name": "Name",
+        "description": "Description",
+        "url": "Url",
+        "OrganizationalUnits": "Organizational Units"
+      },
+      "home": {
+        "subtitle": "Describe funding agency",
+        "title": "Funding agency"
+      },
+      "notification": {
+        "resource": {
+          "create": "Funding agency created with success",
+          "delete": "Funding agency deleted with success",
+          "update": "Role updated with success"
+        }
+      },
+      "table": {
+        "header": {
+          "acronym": "Acronym",
+          "name": "Name"
+        }
+      }
     }
   },
   "app": {
@@ -495,6 +535,13 @@
         "edit": "Edit",
         "list": "List",
         "root": "Roles"
+      },
+      "funding-agencies": {
+        "create": "Create funding agency",
+        "detail": "Detail",
+        "edit": "Edit",
+        "list": "List",
+        "root": "Funding agencies"
       }
     },
     "deposit": {
diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json
index 00ee03623..a4e81a494 100644
--- a/src/assets/i18n/fr.json
+++ b/src/assets/i18n/fr.json
@@ -422,6 +422,46 @@
           "update": "Role mis à jour avec succès"
         }
       }
+    },
+    "funding-agencies": {
+      "button": {
+        "delete": "Supprimer",
+        "edit": "Modifier",
+        "new": "Créer Agence",
+        "refresh": "Rafraichir"
+      },
+      "dialog": {
+        "delete": {
+          "cancel": "Annuler",
+          "confirm": "Oui",
+          "message": "Êtes-vous sûr de vouloir supprimer l'agence '{{name}}'?",
+          "title": "Confirmer suppresion"
+        }
+      },
+      "form": {
+        "acronym": "Acronyme",
+        "name": "Nom",
+        "description": "Description",
+        "url": "Url",
+        "OrganizationalUnits": "Unitées Organisationnelles"
+      },
+      "home": {
+        "subtitle": "Décrit l'utilisateur",
+        "title": "Utilisateur"
+      },
+      "notification": {
+        "resource": {
+          "create": "Agence créé avec succès",
+          "delete": "Agence supprimé avec succès",
+          "update": "Agence mis à jour avec succès"
+        }
+      },
+      "table": {
+        "header": {
+          "acronym": "Acronyme",
+          "name": "Nom"
+        }
+      }
     }
   },
   "app": {
@@ -495,6 +535,13 @@
         "edit": "Modifier",
         "list": "Liste",
         "root": "Roles"
+      },
+      "funding-agencies": {
+        "create": "Créer agence financement",
+        "detail": "Détail",
+        "edit": "Modifier",
+        "list": "Liste",
+        "root": "Agences financements"
       }
     },
     "deposit": {
-- 
GitLab