From 2d64295506639b9e4cd02d1134e8144575d1f37f Mon Sep 17 00:00:00 2001
From: Roma
Date: Fri, 14 Mar 2025 17:03:26 +0200
Subject: [PATCH 01/14] refactor(developer-apps): Changed structure of
developer apps component hierarchy
---
.../developer-app-details.component.html | 1 +
.../developer-app-details.component.scss | 0
.../developer-app-details.component.spec.ts | 22 ++++++++++++++++++
.../developer-app-details.component.ts | 10 ++++++++
.../developer-apps-container.component.html | 6 +++++
...> developer-apps-container.component.scss} | 18 ---------------
...eveloper-apps-container.component.spec.ts} | 10 ++++----
.../developer-apps-container.component.ts | 12 ++++++++++
.../developer-apps-list.component.html} | 15 +++++-------
.../developer-apps-list.component.scss | 22 ++++++++++++++++++
.../developer-apps-list.component.spec.ts | 22 ++++++++++++++++++
.../developer-apps-list.component.ts} | 11 +++++----
.../developer-apps/developer-apps.route.ts | 23 +++++++++++++++++++
src/app/features/settings/settings.routes.ts | 9 ++------
14 files changed, 137 insertions(+), 44 deletions(-)
create mode 100644 src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
create mode 100644 src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss
create mode 100644 src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.spec.ts
create mode 100644 src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
create mode 100644 src/app/features/settings/developer-apps/developer-apps-container.component.html
rename src/app/features/settings/developer-apps/{developer-apps.component.scss => developer-apps-container.component.scss} (61%)
rename src/app/features/settings/developer-apps/{developer-apps.component.spec.ts => developer-apps-container.component.spec.ts} (52%)
create mode 100644 src/app/features/settings/developer-apps/developer-apps-container.component.ts
rename src/app/features/settings/developer-apps/{developer-apps.component.html => developer-apps-list/developer-apps-list.component.html} (65%)
create mode 100644 src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
create mode 100644 src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.spec.ts
rename src/app/features/settings/developer-apps/{developer-apps.component.ts => developer-apps-list/developer-apps-list.component.ts} (76%)
create mode 100644 src/app/features/settings/developer-apps/developer-apps.route.ts
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
new file mode 100644
index 000000000..6aea59f16
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
@@ -0,0 +1 @@
+developer-application-details works!
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.spec.ts b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.spec.ts
new file mode 100644
index 000000000..bebf34b45
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DeveloperAppDetailsComponent } from './developer-app-details.component';
+
+describe('DeveloperApplicationDetailsComponent', () => {
+ let component: DeveloperAppDetailsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [DeveloperAppDetailsComponent],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(DeveloperAppDetailsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
new file mode 100644
index 000000000..c6f8e1fde
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
@@ -0,0 +1,10 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+
+@Component({
+ selector: 'osf-developer-application-details',
+ imports: [],
+ templateUrl: './developer-app-details.component.html',
+ styleUrl: './developer-app-details.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DeveloperAppDetailsComponent {}
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.html b/src/app/features/settings/developer-apps/developer-apps-container.component.html
new file mode 100644
index 000000000..2a254cdd7
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.html
@@ -0,0 +1,6 @@
+
+
diff --git a/src/app/features/settings/developer-apps/developer-apps.component.scss b/src/app/features/settings/developer-apps/developer-apps-container.component.scss
similarity index 61%
rename from src/app/features/settings/developer-apps/developer-apps.component.scss
rename to src/app/features/settings/developer-apps/developer-apps-container.component.scss
index a4448def7..0bf7ef49e 100644
--- a/src/app/features/settings/developer-apps/developer-apps.component.scss
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.scss
@@ -24,22 +24,4 @@
font-size: 2.6rem;
}
}
-
- .content {
- margin: 1.7rem;
- color: var.$dark-blue-1;
-
- p {
- margin-bottom: 1.7rem;
- }
-
- .applications-container {
- @include mix.flex-column;
- gap: 0.85rem;
-
- .card-body {
- @include mix.flex-center-between;
- }
- }
- }
}
diff --git a/src/app/features/settings/developer-apps/developer-apps.component.spec.ts b/src/app/features/settings/developer-apps/developer-apps-container.component.spec.ts
similarity index 52%
rename from src/app/features/settings/developer-apps/developer-apps.component.spec.ts
rename to src/app/features/settings/developer-apps/developer-apps-container.component.spec.ts
index 877f51a84..e481631a6 100644
--- a/src/app/features/settings/developer-apps/developer-apps.component.spec.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.spec.ts
@@ -1,17 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { DeveloperAppsComponent } from './developer-apps.component';
+import { DeveloperAppsContainerComponent } from './developer-apps-container.component';
describe('DeveloperAppsComponent', () => {
- let component: DeveloperAppsComponent;
- let fixture: ComponentFixture;
+ let component: DeveloperAppsContainerComponent;
+ let fixture: ComponentFixture;
beforeEach(async () => {
await TestBed.configureTestingModule({
- imports: [DeveloperAppsComponent],
+ imports: [DeveloperAppsContainerComponent],
}).compileComponents();
- fixture = TestBed.createComponent(DeveloperAppsComponent);
+ fixture = TestBed.createComponent(DeveloperAppsContainerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.ts b/src/app/features/settings/developer-apps/developer-apps-container.component.ts
new file mode 100644
index 000000000..164748cee
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.ts
@@ -0,0 +1,12 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { Button } from 'primeng/button';
+import { RouterOutlet } from '@angular/router';
+
+@Component({
+ selector: 'osf-developer-apps',
+ imports: [Button, RouterOutlet],
+ templateUrl: './developer-apps-container.component.html',
+ styleUrl: './developer-apps-container.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DeveloperAppsContainerComponent {}
diff --git a/src/app/features/settings/developer-apps/developer-apps.component.html b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
similarity index 65%
rename from src/app/features/settings/developer-apps/developer-apps.component.html
rename to src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
index 7ab621ed7..269647be7 100644
--- a/src/app/features/settings/developer-apps/developer-apps.component.html
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
@@ -1,9 +1,4 @@
-
-
+
Third-party web applications can connect to the OSF on behalf of users via
the OAuth 2.0 web application flow.
@@ -13,12 +8,14 @@
Developer apps
@for (developerApp of developerApplications; track $index) {
- {{ developerApp }}
+
+ {{ developerApp }}
+
Delete
+ />
}
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
new file mode 100644
index 000000000..890c1dc17
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
@@ -0,0 +1,22 @@
+@use "assets/styles/variables" as var;
+@use "assets/styles/mixins" as mix;
+
+.content-container {
+ margin: 1.7rem;
+ color: var.$dark-blue-1;
+
+ p {
+ margin-bottom: 1.7rem;
+ }
+
+ .applications-container {
+ @include mix.flex-column;
+ gap: 0.85rem;
+
+ p-card {
+ .card-body {
+ @include mix.flex-center-between;
+ }
+ }
+ }
+}
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.spec.ts b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.spec.ts
new file mode 100644
index 000000000..11b7fe2fb
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DeveloperAppsListComponent } from './developer-apps-list.component';
+
+describe('DeveloperApplicationsListComponent', () => {
+ let component: DeveloperAppsListComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [DeveloperAppsListComponent],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(DeveloperAppsListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/features/settings/developer-apps/developer-apps.component.ts b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
similarity index 76%
rename from src/app/features/settings/developer-apps/developer-apps.component.ts
rename to src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
index a9d59f78c..01aabb5fc 100644
--- a/src/app/features/settings/developer-apps/developer-apps.component.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
@@ -1,15 +1,16 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Button } from 'primeng/button';
import { Card } from 'primeng/card';
+import { RouterLink } from '@angular/router';
@Component({
- selector: 'osf-developer-apps',
- imports: [Button, Card],
- templateUrl: './developer-apps.component.html',
- styleUrl: './developer-apps.component.scss',
+ selector: 'osf-developer-applications-list',
+ imports: [Button, Card, RouterLink],
+ templateUrl: './developer-apps-list.component.html',
+ styleUrl: './developer-apps-list.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class DeveloperAppsComponent {
+export class DeveloperAppsListComponent {
developerApplications: string[] = [
'Developer app name example',
'Developer app name example',
diff --git a/src/app/features/settings/developer-apps/developer-apps.route.ts b/src/app/features/settings/developer-apps/developer-apps.route.ts
new file mode 100644
index 000000000..0e3c87d52
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-apps.route.ts
@@ -0,0 +1,23 @@
+import { Route } from '@angular/router';
+import { DeveloperAppsContainerComponent } from '@osf/features/settings/developer-apps/developer-apps-container.component';
+
+export const developerAppsRoute: Route = {
+ path: 'developer-apps',
+ component: DeveloperAppsContainerComponent,
+ children: [
+ {
+ path: '',
+ loadComponent: () =>
+ import('./developer-apps-list/developer-apps-list.component').then(
+ (c) => c.DeveloperAppsListComponent,
+ ),
+ },
+ {
+ path: ':id/details',
+ loadComponent: () =>
+ import('./developer-app-details/developer-app-details.component').then(
+ (c) => c.DeveloperAppDetailsComponent,
+ ),
+ },
+ ],
+};
diff --git a/src/app/features/settings/settings.routes.ts b/src/app/features/settings/settings.routes.ts
index 6922327a2..12d4fc4f9 100644
--- a/src/app/features/settings/settings.routes.ts
+++ b/src/app/features/settings/settings.routes.ts
@@ -1,5 +1,6 @@
import { Routes } from '@angular/router';
import { SettingsContainerComponent } from '@osf/features/settings/settings-container.component';
+import { developerAppsRoute } from '@osf/features/settings/developer-apps/developer-apps.route';
export const settingsRoutes: Routes = [
{
@@ -20,13 +21,7 @@ export const settingsRoutes: Routes = [
(c) => c.AccountSettingsComponent,
),
},
- {
- path: 'developer-apps',
- loadComponent: () =>
- import('./developer-apps/developer-apps.component').then(
- (mod) => mod.DeveloperAppsComponent,
- ),
- },
+ developerAppsRoute,
],
},
];
From 9016dd88d115a8aec3656f5511b88fbec5623007 Mon Sep 17 00:00:00 2001
From: Roma
Date: Tue, 18 Mar 2025 15:25:40 +0200
Subject: [PATCH 02/14] feat(developer-apps): Finished developer Apps List
page, started working on details page
---
.../breadcrumb/breadcrumb.component.ts | 16 +++-
.../developer-app-details.component.html | 94 ++++++++++++++++++-
.../developer-app-details.component.scss | 41 ++++++++
.../developer-app-details.component.ts | 50 +++++++++-
.../developer-apps/developer-app.entity.ts | 4 +
.../developer-apps-container.component.html | 13 ++-
.../developer-apps-container.component.scss | 21 -----
.../developer-apps-container.component.ts | 10 +-
.../developer-apps-list.component.html | 21 +++--
.../developer-apps-list.component.scss | 20 +++-
.../developer-apps-list.component.ts | 56 ++++++-----
src/assets/styles/overrides/iconfield.scss | 18 ++++
src/assets/styles/styles.scss | 1 +
13 files changed, 297 insertions(+), 68 deletions(-)
create mode 100644 src/app/features/settings/developer-apps/developer-app.entity.ts
create mode 100644 src/assets/styles/overrides/iconfield.scss
diff --git a/src/app/core/components/breadcrumb/breadcrumb.component.ts b/src/app/core/components/breadcrumb/breadcrumb.component.ts
index 06af64b2d..21ace7a94 100644
--- a/src/app/core/components/breadcrumb/breadcrumb.component.ts
+++ b/src/app/core/components/breadcrumb/breadcrumb.component.ts
@@ -1,5 +1,6 @@
-import { Component, computed, inject, signal } from '@angular/core';
-import { Router } from '@angular/router';
+import { Component, computed, DestroyRef, inject, signal } from '@angular/core';
+import { NavigationEnd, Router } from '@angular/router';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({
selector: 'osf-breadcrumb',
@@ -9,8 +10,19 @@ import { Router } from '@angular/router';
})
export class BreadcrumbComponent {
#router = inject(Router);
+ #destroyRef = inject(DestroyRef);
protected readonly url = signal(this.#router.url);
protected readonly parsedUrl = computed(() => {
return this.url().split('/').filter(Boolean);
});
+
+ constructor() {
+ this.#router.events
+ .pipe(takeUntilDestroyed(this.#destroyRef))
+ .subscribe((event) => {
+ if (event instanceof NavigationEnd) {
+ this.url.set(this.#router.url);
+ }
+ });
+ }
}
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
index 6aea59f16..561ac0d44 100644
--- a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
@@ -1 +1,93 @@
-developer-application-details works!
+
+
+
+ Back to list of developer apps
+
+
+
+
+ {{ developerApp().name + developerAppId() }}
+
+
+
+
+
+
+
+
+
+
+ Client Secret
+
+
+ The client secret is available only to you. Keep it private and do not
+ share it.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss
index e69de29bb..1a8f012ed 100644
--- a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss
@@ -0,0 +1,41 @@
+@use "assets/styles/variables" as var;
+@use "assets/styles/mixins" as mix;
+
+.content-container {
+ padding: 1.7rem;
+ color: var.$dark-blue-1;
+ background-color: var.$white;
+
+ .navigation-bar-container {
+ margin-bottom: 24px;
+ }
+
+ .tittle-container {
+ @include mix.flex-center-between;
+ margin-bottom: 48px;
+ }
+
+ .cards-container {
+ @include mix.flex-column;
+ gap: 24px;
+
+ .card-body {
+ h2 {
+ margin-bottom: 24px;
+ }
+
+ p {
+ margin-bottom: 12px;
+ }
+
+ .client-secret-container {
+ @include mix.flex-align-center;
+ gap: 12px;
+ }
+
+ .card-actions {
+ @include mix.flex-center-right;
+ }
+ }
+ }
+}
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
index c6f8e1fde..9e8f802b5 100644
--- a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
@@ -1,10 +1,54 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ computed,
+ DestroyRef,
+ inject,
+ OnInit,
+ signal,
+} from '@angular/core';
+import { DeveloperApp } from '@osf/features/settings/developer-apps/developer-app.entity';
+import { Button } from 'primeng/button';
+import { Card } from 'primeng/card';
+import { ActivatedRoute, RouterLink } from '@angular/router';
+import { InputText } from 'primeng/inputtext';
+import { IconField } from 'primeng/iconfield';
+import { InputIcon } from 'primeng/inputicon';
@Component({
selector: 'osf-developer-application-details',
- imports: [],
+ imports: [Button, Card, RouterLink, InputText, IconField, InputIcon],
templateUrl: './developer-app-details.component.html',
styleUrl: './developer-app-details.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class DeveloperAppDetailsComponent {}
+export class DeveloperAppDetailsComponent implements OnInit {
+ private readonly destroyRef = inject(DestroyRef);
+ private readonly activatedRoute = inject(ActivatedRoute);
+ developerAppId = signal(null);
+ developerApp = signal({
+ id: '1',
+ name: 'Example name',
+ });
+ isClientSecretVisible = signal(false);
+ clientSecret = signal('asdfasdfasdfasdfasdf');
+ hiddenClientSecret = computed(() =>
+ '*'.repeat(this.clientSecret().length),
+ );
+
+ ngOnInit(): void {
+ this.developerAppId.set(this.activatedRoute.snapshot.params['id']);
+ }
+
+ onDeleteAppBtnClicked(): void {
+ //TODO integrate API
+ }
+
+ onResetClientSecretBtnClicked(): void {
+ //TODO integrate API
+ }
+
+ copyClientId(): void {
+ console.log('copy client id');
+ }
+}
diff --git a/src/app/features/settings/developer-apps/developer-app.entity.ts b/src/app/features/settings/developer-apps/developer-app.entity.ts
new file mode 100644
index 000000000..c4ad86de6
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-app.entity.ts
@@ -0,0 +1,4 @@
+export interface DeveloperApp {
+ id: string;
+ name: string;
+}
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.html b/src/app/features/settings/developer-apps/developer-apps-container.component.html
index 2a254cdd7..7c46eb6b1 100644
--- a/src/app/features/settings/developer-apps/developer-apps-container.component.html
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.html
@@ -1,6 +1,9 @@
-
+
+
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.scss b/src/app/features/settings/developer-apps/developer-apps-container.component.scss
index 0bf7ef49e..43b3dda99 100644
--- a/src/app/features/settings/developer-apps/developer-apps-container.component.scss
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.scss
@@ -3,25 +3,4 @@
:host {
@include mix.flex-column;
- flex: 1;
-
- .header {
- @include mix.flex-center-between;
- width: 100%;
- padding: 7.14rem 1.71rem 3.43rem 1.71rem;
- background: var.$gradient-1;
-
- h1 {
- margin-left: 0.85rem;
- }
-
- p-button {
- margin-left: auto;
- }
-
- i {
- color: var.$dark-blue-1;
- font-size: 2.6rem;
- }
- }
}
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.ts b/src/app/features/settings/developer-apps/developer-apps-container.component.ts
index 164748cee..89c2fe49a 100644
--- a/src/app/features/settings/developer-apps/developer-apps-container.component.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.ts
@@ -1,12 +1,16 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { Button } from 'primeng/button';
import { RouterOutlet } from '@angular/router';
+import { SubHeaderComponent } from '@shared/components/sub-header/sub-header.component';
@Component({
selector: 'osf-developer-apps',
- imports: [Button, RouterOutlet],
+ imports: [RouterOutlet, SubHeaderComponent],
templateUrl: './developer-apps-container.component.html',
styleUrl: './developer-apps-container.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class DeveloperAppsContainerComponent {}
+export class DeveloperAppsContainerComponent {
+ onCreateDeveloperAppBtnClicked(): void {
+ //TODO integrate API
+ }
+}
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
index 269647be7..e98b425b9 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
@@ -5,17 +5,20 @@
- @for (developerApp of developerApplications; track $index) {
+ @for (developerApp of developerApplications(); track $index) {
-
}
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
index 890c1dc17..392eb7da6 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
@@ -2,8 +2,9 @@
@use "assets/styles/mixins" as mix;
.content-container {
- margin: 1.7rem;
+ padding: 1.7rem;
color: var.$dark-blue-1;
+ background-color: var.$white;
p {
margin-bottom: 1.7rem;
@@ -15,7 +16,22 @@
p-card {
.card-body {
- @include mix.flex-center-between;
+ &.mobile {
+ @include mix.flex-column;
+
+ a {
+ align-self: flex-start;
+ }
+
+ .button-container {
+ align-self: flex-end;
+ width: 50%;
+ }
+ }
+
+ &:not(.mobile) {
+ @include mix.flex-center-between;
+ }
}
}
}
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
index 01aabb5fc..07e5b7e4f 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
@@ -1,37 +1,49 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ inject,
+ signal,
+} from '@angular/core';
import { Button } from 'primeng/button';
import { Card } from 'primeng/card';
import { RouterLink } from '@angular/router';
+import { DeveloperApp } from '@osf/features/settings/developer-apps/developer-app.entity';
+import { IS_XSMALL } from '@shared/utils/breakpoints.tokens';
+import { toSignal } from '@angular/core/rxjs-interop';
+import { NgClass } from '@angular/common';
@Component({
selector: 'osf-developer-applications-list',
- imports: [Button, Card, RouterLink],
+ imports: [Button, Card, RouterLink, NgClass],
templateUrl: './developer-apps-list.component.html',
styleUrl: './developer-apps-list.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeveloperAppsListComponent {
- developerApplications: string[] = [
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- 'Developer app name example',
- ];
+ #isXSmall$ = inject(IS_XSMALL);
+ isXSmall = toSignal(this.#isXSmall$);
- onDeleteDeveloperApp(developerApp: string): void {
- console.log('delete', developerApp);
+ developerApplications = signal([
+ {
+ id: '1',
+ name: 'Developer app name example',
+ },
+ {
+ id: '2',
+ name: 'Developer app name example',
+ },
+ {
+ id: '3',
+ name: 'Developer app name example',
+ },
+ {
+ id: '4',
+ name: 'Developer app name example',
+ },
+ ]);
+
+ onDeleteAppBtnClicked(developerAppId: string): void {
+ console.log('delete', developerAppId);
//TODO implement api integration
}
}
diff --git a/src/assets/styles/overrides/iconfield.scss b/src/assets/styles/overrides/iconfield.scss
new file mode 100644
index 000000000..91c63a85f
--- /dev/null
+++ b/src/assets/styles/overrides/iconfield.scss
@@ -0,0 +1,18 @@
+@use "assets/styles/variables" as var;
+
+.p-iconfield {
+ display: inline-block;
+
+ .p-inputtext {
+ width: inherit !important;
+ }
+
+ .p-inputicon {
+ cursor: pointer;
+ color: var.$dark-blue-1;
+
+ i {
+ font-size: 1.2rem;
+ }
+ }
+}
diff --git a/src/assets/styles/styles.scss b/src/assets/styles/styles.scss
index 33aa0c946..ae0e511c7 100644
--- a/src/assets/styles/styles.scss
+++ b/src/assets/styles/styles.scss
@@ -9,6 +9,7 @@
@use "./overrides/message";
@use "./overrides/drawer";
@use "./overrides/card";
+@use "./overrides/iconfield";
@layer base, primeng, reset;
From 9a8beff0b61f5fefed7a2d1392908a3d27755387 Mon Sep 17 00:00:00 2001
From: Roma
Date: Wed, 19 Mar 2025 13:25:30 +0200
Subject: [PATCH 03/14] style(primeng-override): Added styles for button, card
and iconfield
---
src/assets/styles/overrides/button.scss | 8 ++++++++
src/assets/styles/overrides/card.scss | 4 ++++
src/assets/styles/overrides/iconfield.scss | 4 ----
3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/assets/styles/overrides/button.scss b/src/assets/styles/overrides/button.scss
index 49b9e98ef..861231cfc 100644
--- a/src/assets/styles/overrides/button.scss
+++ b/src/assets/styles/overrides/button.scss
@@ -142,6 +142,14 @@
}
.btn-full-width {
+ width: 100%;
+ .p-button {
+ width: 100%;
+ }
+}
+
+.btn-half-width {
+ width: 50%;
.p-button {
width: 100%;
}
diff --git a/src/assets/styles/overrides/card.scss b/src/assets/styles/overrides/card.scss
index 84c630308..2fa01d8af 100644
--- a/src/assets/styles/overrides/card.scss
+++ b/src/assets/styles/overrides/card.scss
@@ -11,3 +11,7 @@
padding: 1.7rem;
}
}
+
+.mobile .p-card .p-card-body {
+ padding: 0.85rem;
+}
diff --git a/src/assets/styles/overrides/iconfield.scss b/src/assets/styles/overrides/iconfield.scss
index 91c63a85f..7781e8f4b 100644
--- a/src/assets/styles/overrides/iconfield.scss
+++ b/src/assets/styles/overrides/iconfield.scss
@@ -3,10 +3,6 @@
.p-iconfield {
display: inline-block;
- .p-inputtext {
- width: inherit !important;
- }
-
.p-inputicon {
cursor: pointer;
color: var.$dark-blue-1;
From 8e49dd22933c87e0d728efc641df967bb33ad383 Mon Sep 17 00:00:00 2001
From: Roma
Date: Wed, 19 Mar 2025 13:38:30 +0200
Subject: [PATCH 04/14] feat(developer-apps): Added create developer app form
component
---
src/app/core/helpers/link-validator.helper.ts | 16 +++++
.../create-developer-app.component.html | 64 +++++++++++++++++
.../create-developer-app.component.scss | 0
.../create-developer-app.component.spec.ts | 22 ++++++
.../create-developer-app.component.ts | 71 +++++++++++++++++++
.../developer-apps/developer-app.entities.ts | 24 +++++++
.../developer-apps/developer-app.entity.ts | 4 --
7 files changed, 197 insertions(+), 4 deletions(-)
create mode 100644 src/app/core/helpers/link-validator.helper.ts
create mode 100644 src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.html
create mode 100644 src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.scss
create mode 100644 src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.spec.ts
create mode 100644 src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.ts
create mode 100644 src/app/features/settings/developer-apps/developer-app.entities.ts
delete mode 100644 src/app/features/settings/developer-apps/developer-app.entity.ts
diff --git a/src/app/core/helpers/link-validator.helper.ts b/src/app/core/helpers/link-validator.helper.ts
new file mode 100644
index 000000000..a7c406224
--- /dev/null
+++ b/src/app/core/helpers/link-validator.helper.ts
@@ -0,0 +1,16 @@
+import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
+
+export function linkValidator(): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ const value = control.value;
+ if (!value) {
+ return null;
+ }
+
+ const urlPattern = /^(https?):\/\/.+/i;
+
+ const isValid = urlPattern.test(value);
+
+ return isValid ? null : { link: true };
+ };
+}
diff --git a/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.html b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.html
new file mode 100644
index 000000000..b80a456e8
--- /dev/null
+++ b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.html
@@ -0,0 +1,64 @@
+
diff --git a/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.scss b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.spec.ts b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.spec.ts
new file mode 100644
index 000000000..06cae3a5e
--- /dev/null
+++ b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CreateDeveloperAppComponent } from './create-developer-app.component';
+
+describe('CreateDeveloperAppComponent', () => {
+ let component: CreateDeveloperAppComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [CreateDeveloperAppComponent],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(CreateDeveloperAppComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.ts b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.ts
new file mode 100644
index 000000000..063a2199d
--- /dev/null
+++ b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.ts
@@ -0,0 +1,71 @@
+import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
+import { DynamicDialogRef } from 'primeng/dynamicdialog';
+import { Button } from 'primeng/button';
+import { InputText } from 'primeng/inputtext';
+import {
+ FormControl,
+ FormGroup,
+ ReactiveFormsModule,
+ Validators,
+} from '@angular/forms';
+import {
+ DeveloperAppForm,
+ DeveloperAppFormFormControls,
+} from '@osf/features/settings/developer-apps/developer-app.entities';
+import { linkValidator } from '@core/helpers/link-validator.helper';
+
+@Component({
+ selector: 'osf-create-developer-app',
+ imports: [Button, InputText, ReactiveFormsModule],
+ templateUrl: './create-developer-app.component.html',
+ styleUrl: './create-developer-app.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class CreateDeveloperAppComponent {
+ readonly dialogRef = inject(DynamicDialogRef);
+ protected readonly DeveloperAppFormFormControls =
+ DeveloperAppFormFormControls;
+
+ readonly createAppForm: DeveloperAppForm = new FormGroup({
+ [DeveloperAppFormFormControls.AppName]: new FormControl('', {
+ nonNullable: true,
+ validators: [Validators.required],
+ }),
+ [DeveloperAppFormFormControls.ProjectHomePageUrl]: new FormControl('', {
+ nonNullable: true,
+ validators: [Validators.required, linkValidator()],
+ }),
+ [DeveloperAppFormFormControls.AppDescription]: new FormControl('', {
+ nonNullable: false,
+ }),
+ [DeveloperAppFormFormControls.AuthorizationCallbackUrl]: new FormControl(
+ '',
+ {
+ nonNullable: true,
+ validators: [Validators.required, linkValidator()],
+ },
+ ),
+ });
+
+ submitForm(): void {
+ if (!this.createAppForm.valid) {
+ this.createAppForm.markAllAsTouched();
+ this.createAppForm
+ .get([DeveloperAppFormFormControls.AppName])
+ ?.markAsDirty();
+ this.createAppForm
+ .get(DeveloperAppFormFormControls.ProjectHomePageUrl)
+ ?.markAsDirty();
+ this.createAppForm
+ .get(DeveloperAppFormFormControls.AppDescription)
+ ?.markAsDirty();
+ this.createAppForm
+ .get(DeveloperAppFormFormControls.AuthorizationCallbackUrl)
+ ?.markAsDirty();
+ return;
+ }
+
+ //TODO integrate API
+ this.dialogRef.close();
+ }
+}
diff --git a/src/app/features/settings/developer-apps/developer-app.entities.ts b/src/app/features/settings/developer-apps/developer-app.entities.ts
new file mode 100644
index 000000000..200a7ff5e
--- /dev/null
+++ b/src/app/features/settings/developer-apps/developer-app.entities.ts
@@ -0,0 +1,24 @@
+import { FormControl, FormGroup } from '@angular/forms';
+import { StringOrNull } from '@core/helpers/types.helper';
+
+export interface DeveloperApp {
+ id: string;
+ appName: string;
+ projHomePageUrl: string;
+ appDescription: StringOrNull;
+ authorizationCallbackUrl: string;
+}
+
+export enum DeveloperAppFormFormControls {
+ AppName = 'appName',
+ ProjectHomePageUrl = 'projHomePageUrl',
+ AppDescription = 'appDescription',
+ AuthorizationCallbackUrl = 'authorizationCallbackUrl',
+}
+
+export type DeveloperAppForm = FormGroup<{
+ [DeveloperAppFormFormControls.AppName]: FormControl;
+ [DeveloperAppFormFormControls.ProjectHomePageUrl]: FormControl;
+ [DeveloperAppFormFormControls.AppDescription]: FormControl;
+ [DeveloperAppFormFormControls.AuthorizationCallbackUrl]: FormControl;
+}>;
diff --git a/src/app/features/settings/developer-apps/developer-app.entity.ts b/src/app/features/settings/developer-apps/developer-app.entity.ts
deleted file mode 100644
index c4ad86de6..000000000
--- a/src/app/features/settings/developer-apps/developer-app.entity.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface DeveloperApp {
- id: string;
- name: string;
-}
From 882d8d8f99e25704751b0e043866a82df4968b21 Mon Sep 17 00:00:00 2001
From: Roma
Date: Wed, 19 Mar 2025 13:42:07 +0200
Subject: [PATCH 05/14] style(developer-apps): Adapted developer apps component
for mobile
---
.../developer-apps-list/developer-apps-list.component.html | 4 ++--
.../developer-apps-list/developer-apps-list.component.scss | 5 +++++
.../developer-apps-list/developer-apps-list.component.ts | 3 +--
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
index e98b425b9..551bf2717 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
@@ -1,4 +1,4 @@
-
+
Third-party web applications can connect to the OSF on behalf of users via
the OAuth 2.0 web application flow.
@@ -7,7 +7,7 @@
@for (developerApp of developerApplications(); track $index) {
-
+
{{ developerApp.name }}
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
index 392eb7da6..e327dbce6 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
@@ -6,6 +6,10 @@
color: var.$dark-blue-1;
background-color: var.$white;
+ &.mobile {
+ padding: 1rem;
+ }
+
p {
margin-bottom: 1.7rem;
}
@@ -18,6 +22,7 @@
.card-body {
&.mobile {
@include mix.flex-column;
+ gap: 0.85rem;
a {
align-self: flex-start;
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
index 07e5b7e4f..d98fcf987 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
@@ -10,11 +10,10 @@ import { RouterLink } from '@angular/router';
import { DeveloperApp } from '@osf/features/settings/developer-apps/developer-app.entity';
import { IS_XSMALL } from '@shared/utils/breakpoints.tokens';
import { toSignal } from '@angular/core/rxjs-interop';
-import { NgClass } from '@angular/common';
@Component({
selector: 'osf-developer-applications-list',
- imports: [Button, Card, RouterLink, NgClass],
+ imports: [Button, Card, RouterLink],
templateUrl: './developer-apps-list.component.html',
styleUrl: './developer-apps-list.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
From 88d995c58405ef5256d0f2e5a8364bca8b242b28 Mon Sep 17 00:00:00 2001
From: Roma
Date: Wed, 19 Mar 2025 13:49:14 +0200
Subject: [PATCH 06/14] feat(developer-apps): Added create app dialog
---
.../developer-apps-container.component.html | 2 +-
.../developer-apps-container.component.ts | 18 +++++++++++++++---
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.html b/src/app/features/settings/developer-apps/developer-apps-container.component.html
index 7c46eb6b1..622c11cec 100644
--- a/src/app/features/settings/developer-apps/developer-apps-container.component.html
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.html
@@ -3,7 +3,7 @@
[buttonLabel]="'Create Developer App'"
[title]="'Developer apps'"
[icon]="'settings'"
- (buttonClick)="onCreateDeveloperAppBtnClicked()"
+ (buttonClick)="createDeveloperApp()"
/>
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.ts b/src/app/features/settings/developer-apps/developer-apps-container.component.ts
index 89c2fe49a..50c64aa9d 100644
--- a/src/app/features/settings/developer-apps/developer-apps-container.component.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.ts
@@ -1,16 +1,28 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { SubHeaderComponent } from '@shared/components/sub-header/sub-header.component';
+import { DialogService } from 'primeng/dynamicdialog';
+import { CreateDeveloperAppComponent } from '@osf/features/settings/developer-apps/create-developer-app/create-developer-app.component';
@Component({
selector: 'osf-developer-apps',
imports: [RouterOutlet, SubHeaderComponent],
templateUrl: './developer-apps-container.component.html',
styleUrl: './developer-apps-container.component.scss',
+ providers: [DialogService],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeveloperAppsContainerComponent {
- onCreateDeveloperAppBtnClicked(): void {
- //TODO integrate API
+ private readonly dialogService = inject(DialogService);
+
+ createDeveloperApp(): void {
+ this.dialogService.open(CreateDeveloperAppComponent, {
+ width: '448px',
+ focusOnShow: false,
+ header: 'Create Developer App',
+ closeOnEscape: true,
+ modal: true,
+ closable: true,
+ });
}
}
From bab0d9b447e40b2ce1e34ae5eaeed5c8aba5706c Mon Sep 17 00:00:00 2001
From: Roma
Date: Wed, 19 Mar 2025 13:54:04 +0200
Subject: [PATCH 07/14] refactor(developer-apps): Refactored developer apps
component
---
.../developer-apps-list.component.html | 4 ++--
.../developer-apps-list.component.ts | 22 +++++++++----------
2 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
index 551bf2717..5b3b79394 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
@@ -9,14 +9,14 @@
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
index d98fcf987..5ab2aabad 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
@@ -7,7 +7,7 @@ import {
import { Button } from 'primeng/button';
import { Card } from 'primeng/card';
import { RouterLink } from '@angular/router';
-import { DeveloperApp } from '@osf/features/settings/developer-apps/developer-app.entity';
+import { DeveloperApp } from '@osf/features/settings/developer-apps/developer-app.entities';
import { IS_XSMALL } from '@shared/utils/breakpoints.tokens';
import { toSignal } from '@angular/core/rxjs-interop';
@@ -25,23 +25,21 @@ export class DeveloperAppsListComponent {
developerApplications = signal([
{
id: '1',
- name: 'Developer app name example',
+ appName: 'Developer app name example',
+ projHomePageUrl: 'https://example.com',
+ appDescription: 'Example description',
+ authorizationCallbackUrl: 'https://example.com/callback',
},
{
id: '2',
- name: 'Developer app name example',
- },
- {
- id: '3',
- name: 'Developer app name example',
- },
- {
- id: '4',
- name: 'Developer app name example',
+ appName: 'Developer app name example',
+ projHomePageUrl: 'https://example.com',
+ appDescription: 'Example description',
+ authorizationCallbackUrl: 'https://example.com/callback',
},
]);
- onDeleteAppBtnClicked(developerAppId: string): void {
+ deleteApp(developerAppId: string): void {
console.log('delete', developerAppId);
//TODO implement api integration
}
From 76a000501a0bcb78cf055d18f2505648752174e7 Mon Sep 17 00:00:00 2001
From: Roma
Date: Wed, 19 Mar 2025 17:22:13 +0200
Subject: [PATCH 08/14] feat(developer-apps): Added edit app form, adapted for
mobile
---
.../developer-app-details.component.html | 100 ++++++++++++++---
.../developer-app-details.component.scss | 28 ++++-
.../developer-app-details.component.ts | 106 ++++++++++++++++--
3 files changed, 202 insertions(+), 32 deletions(-)
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
index 561ac0d44..b888610fd 100644
--- a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
@@ -1,36 +1,37 @@
-
+
+
Back to list of developer apps
-
- {{ developerApp().name + developerAppId() }}
+
+ {{ developerApp().appName + developerAppId() }}
-
-
+
@@ -84,9 +89,68 @@ Client Secret
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss
index 1a8f012ed..6b9899f4a 100644
--- a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.scss
@@ -6,31 +6,47 @@
color: var.$dark-blue-1;
background-color: var.$white;
+ &.mobile {
+ padding: 1rem;
+ }
+
.navigation-bar-container {
- margin-bottom: 24px;
+ margin-bottom: 1.7rem;
}
.tittle-container {
@include mix.flex-center-between;
- margin-bottom: 48px;
+ margin-bottom: 3.4rem;
+
+ &.mobile {
+ @include mix.flex-column;
+ align-items: inherit;
+ gap: 1.7rem;
+ }
}
.cards-container {
@include mix.flex-column;
- gap: 24px;
+ gap: 1.7rem;
.card-body {
h2 {
- margin-bottom: 24px;
+ margin-bottom: 1.7rem;
}
p {
- margin-bottom: 12px;
+ margin-bottom: 0.85rem;
}
.client-secret-container {
@include mix.flex-align-center;
- gap: 12px;
+ gap: 0.85rem;
+ margin-bottom: 1.7rem;
+
+ &.mobile {
+ @include mix.flex-column;
+ align-items: start;
+ }
}
.card-actions {
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
index 9e8f802b5..3557de1e4 100644
--- a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
@@ -7,17 +7,42 @@ import {
OnInit,
signal,
} from '@angular/core';
-import { DeveloperApp } from '@osf/features/settings/developer-apps/developer-app.entity';
+import {
+ DeveloperApp,
+ DeveloperAppFormFormControls,
+ DeveloperAppForm,
+} from '@osf/features/settings/developer-apps/developer-app.entities';
import { Button } from 'primeng/button';
import { Card } from 'primeng/card';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { InputText } from 'primeng/inputtext';
import { IconField } from 'primeng/iconfield';
import { InputIcon } from 'primeng/inputicon';
+import { CdkCopyToClipboard } from '@angular/cdk/clipboard';
+import { IS_XSMALL } from '@shared/utils/breakpoints.tokens';
+import { toSignal } from '@angular/core/rxjs-interop';
+import {
+ FormControl,
+ FormGroup,
+ FormsModule,
+ ReactiveFormsModule,
+ Validators,
+} from '@angular/forms';
+import { linkValidator } from '@core/helpers/link-validator.helper';
@Component({
selector: 'osf-developer-application-details',
- imports: [Button, Card, RouterLink, InputText, IconField, InputIcon],
+ imports: [
+ Button,
+ Card,
+ RouterLink,
+ InputText,
+ IconField,
+ InputIcon,
+ CdkCopyToClipboard,
+ FormsModule,
+ ReactiveFormsModule,
+ ],
templateUrl: './developer-app-details.component.html',
styleUrl: './developer-app-details.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -25,30 +50,95 @@ import { InputIcon } from 'primeng/inputicon';
export class DeveloperAppDetailsComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef);
private readonly activatedRoute = inject(ActivatedRoute);
+ private readonly isXSmall$ = inject(IS_XSMALL);
+ protected readonly DeveloperAppFormFormControls =
+ DeveloperAppFormFormControls;
+
+ isXSmall = toSignal(this.isXSmall$);
developerAppId = signal(null);
developerApp = signal({
id: '1',
- name: 'Example name',
+ appName: 'Example name',
+ projHomePageUrl: 'https://example.com',
+ appDescription: 'Example description',
+ authorizationCallbackUrl: 'https://example.com/callback',
});
isClientSecretVisible = signal(false);
- clientSecret = signal('asdfasdfasdfasdfasdf');
+ clientSecret = signal(
+ 'clientsecretclientsecretclientsecretclientsecret',
+ );
+ clientId = signal('clientid');
hiddenClientSecret = computed(() =>
'*'.repeat(this.clientSecret().length),
);
+ readonly editAppForm: DeveloperAppForm = new FormGroup({
+ [DeveloperAppFormFormControls.AppName]: new FormControl(
+ this.developerApp().appName,
+ {
+ nonNullable: true,
+ validators: [Validators.required],
+ },
+ ),
+ [DeveloperAppFormFormControls.ProjectHomePageUrl]: new FormControl(
+ this.developerApp().projHomePageUrl,
+ {
+ nonNullable: true,
+ validators: [Validators.required, linkValidator()],
+ },
+ ),
+ [DeveloperAppFormFormControls.AppDescription]: new FormControl(
+ this.developerApp().appDescription,
+ {
+ nonNullable: false,
+ },
+ ),
+ [DeveloperAppFormFormControls.AuthorizationCallbackUrl]: new FormControl(
+ this.developerApp().authorizationCallbackUrl,
+ {
+ nonNullable: true,
+ validators: [Validators.required, linkValidator()],
+ },
+ ),
+ });
+
ngOnInit(): void {
this.developerAppId.set(this.activatedRoute.snapshot.params['id']);
}
- onDeleteAppBtnClicked(): void {
+ deleteApp(): void {
+ //TODO confirmation dialog
//TODO integrate API
}
- onResetClientSecretBtnClicked(): void {
+ resetClientSecret(): void {
//TODO integrate API
}
- copyClientId(): void {
- console.log('copy client id');
+ clientIdCopiedToClipboard(): void {
+ //TODO maybe show message
+ }
+
+ clientSecretCopiedToClipboard(): void {
+ //TODO maybe show message
+ }
+
+ submitForm(): void {
+ if (!this.editAppForm.valid) {
+ this.editAppForm.markAllAsTouched();
+ this.editAppForm.get(DeveloperAppFormFormControls.AppName)?.markAsDirty();
+ this.editAppForm
+ .get(DeveloperAppFormFormControls.ProjectHomePageUrl)
+ ?.markAsDirty();
+ this.editAppForm
+ .get(DeveloperAppFormFormControls.AppDescription)
+ ?.markAsDirty();
+ this.editAppForm
+ .get(DeveloperAppFormFormControls.AuthorizationCallbackUrl)
+ ?.markAsDirty();
+ return;
+ }
+
+ //TODO integrate API
}
}
From 140e1d671a8592b965fcb411d08e25e5b8fab251 Mon Sep 17 00:00:00 2001
From: Roma
Date: Fri, 21 Mar 2025 11:34:11 +0200
Subject: [PATCH 09/14] feat(developer-apps): Confirmation dialog before
deleting app and resetting secret
---
.../developer-app-details.component.ts | 36 +++++++++++++++++--
.../developer-apps-list.component.html | 2 +-
.../developer-apps-list.component.ts | 21 +++++++++--
3 files changed, 52 insertions(+), 7 deletions(-)
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
index 3557de1e4..1e710eff9 100644
--- a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.ts
@@ -29,6 +29,8 @@ import {
Validators,
} from '@angular/forms';
import { linkValidator } from '@core/helpers/link-validator.helper';
+import { ConfirmationService } from 'primeng/api';
+import { defaultConfirmationConfig } from '@shared/helpers/default-confirmation-config.helper';
@Component({
selector: 'osf-developer-application-details',
@@ -50,6 +52,7 @@ import { linkValidator } from '@core/helpers/link-validator.helper';
export class DeveloperAppDetailsComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef);
private readonly activatedRoute = inject(ActivatedRoute);
+ private readonly confirmationService = inject(ConfirmationService);
private readonly isXSmall$ = inject(IS_XSMALL);
protected readonly DeveloperAppFormFormControls =
DeveloperAppFormFormControls;
@@ -107,12 +110,39 @@ export class DeveloperAppDetailsComponent implements OnInit {
}
deleteApp(): void {
- //TODO confirmation dialog
- //TODO integrate API
+ this.confirmationService.confirm({
+ ...defaultConfirmationConfig,
+ message:
+ "Are you sure you want to delete this developer app? All users' access tokens will be revoked. This cannot be reversed.",
+ header: `Delete App ${this.developerApp().appName}?`,
+ acceptButtonProps: {
+ ...defaultConfirmationConfig.acceptButtonProps,
+ severity: 'danger',
+ label: 'Delete',
+ },
+ accept: () => {
+ //TODO integrate API
+ },
+ });
}
resetClientSecret(): void {
- //TODO integrate API
+ this.confirmationService.confirm({
+ ...defaultConfirmationConfig,
+ message:
+ 'Resetting the client secret will render your application unusable until it is updated with the new client secret,' +
+ ' and all users must reauthorize access. Previously issued access tokens will no longer work.' +
+ ' Are you sure you want to reset the client secret? This cannot be reversed.',
+ header: `Reset Client Secret?`,
+ acceptButtonProps: {
+ ...defaultConfirmationConfig.acceptButtonProps,
+ severity: 'danger',
+ label: 'Reset',
+ },
+ accept: () => {
+ //TODO integrate API
+ },
+ });
}
clientIdCopiedToClipboard(): void {
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
index 5b3b79394..8c19106e4 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.html
@@ -16,7 +16,7 @@ {{ developerApp.appName }}
class="btn-full-width"
label="Delete"
severity="danger"
- (onClick)="deleteApp(developerApp.id)"
+ (onClick)="deleteApp(developerApp)"
/>
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
index 5ab2aabad..cdf7ac554 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.ts
@@ -10,6 +10,8 @@ import { RouterLink } from '@angular/router';
import { DeveloperApp } from '@osf/features/settings/developer-apps/developer-app.entities';
import { IS_XSMALL } from '@shared/utils/breakpoints.tokens';
import { toSignal } from '@angular/core/rxjs-interop';
+import { defaultConfirmationConfig } from '@shared/helpers/default-confirmation-config.helper';
+import { ConfirmationService } from 'primeng/api';
@Component({
selector: 'osf-developer-applications-list',
@@ -19,6 +21,7 @@ import { toSignal } from '@angular/core/rxjs-interop';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeveloperAppsListComponent {
+ private readonly confirmationService = inject(ConfirmationService);
#isXSmall$ = inject(IS_XSMALL);
isXSmall = toSignal(this.#isXSmall$);
@@ -39,8 +42,20 @@ export class DeveloperAppsListComponent {
},
]);
- deleteApp(developerAppId: string): void {
- console.log('delete', developerAppId);
- //TODO implement api integration
+ deleteApp(developerApp: DeveloperApp): void {
+ this.confirmationService.confirm({
+ ...defaultConfirmationConfig,
+ message:
+ "Are you sure you want to delete this developer app? All users' access tokens will be revoked. This cannot be reversed.",
+ header: `Delete App ${developerApp.appName}?`,
+ acceptButtonProps: {
+ ...defaultConfirmationConfig.acceptButtonProps,
+ severity: 'danger',
+ label: 'Delete',
+ },
+ accept: () => {
+ //TODO integrate API
+ },
+ });
}
}
From a5fd4c9becd24df3a260a9510de3fc535282cd39 Mon Sep 17 00:00:00 2001
From: Roma
Date: Fri, 21 Mar 2025 11:34:50 +0200
Subject: [PATCH 10/14] feat(developer-apps): Renamed developer create form
submit button's label
---
.../create-developer-app.component.html | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.html b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.html
index b80a456e8..5aeaa6349 100644
--- a/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.html
+++ b/src/app/features/settings/developer-apps/create-developer-app/create-developer-app.component.html
@@ -48,16 +48,10 @@
From 9dce87d85dbf5162ce57bfc3dd4af8777c06e2fc Mon Sep 17 00:00:00 2001
From: Roma
Date: Fri, 21 Mar 2025 11:35:42 +0200
Subject: [PATCH 11/14] feat(developer-apps): Adjusted create developer app
dialog width for different layouts
---
.../developer-apps-container.component.ts | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.ts b/src/app/features/settings/developer-apps/developer-apps-container.component.ts
index 50c64aa9d..fa654d3a8 100644
--- a/src/app/features/settings/developer-apps/developer-apps-container.component.ts
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.ts
@@ -3,6 +3,8 @@ import { RouterOutlet } from '@angular/router';
import { SubHeaderComponent } from '@shared/components/sub-header/sub-header.component';
import { DialogService } from 'primeng/dynamicdialog';
import { CreateDeveloperAppComponent } from '@osf/features/settings/developer-apps/create-developer-app/create-developer-app.component';
+import { IS_MEDIUM, IS_XSMALL } from '@shared/utils/breakpoints.tokens';
+import { toSignal } from '@angular/core/rxjs-interop';
@Component({
selector: 'osf-developer-apps',
@@ -14,10 +16,21 @@ import { CreateDeveloperAppComponent } from '@osf/features/settings/developer-ap
})
export class DeveloperAppsContainerComponent {
private readonly dialogService = inject(DialogService);
+ isXSmall$ = inject(IS_XSMALL);
+ isMedium$ = inject(IS_MEDIUM);
+ isXSmall = toSignal(this.isXSmall$);
+ isMedium = toSignal(this.isMedium$);
createDeveloperApp(): void {
+ let dialogWidth = '850px';
+ if (this.isXSmall()) {
+ dialogWidth = '345px';
+ } else if (this.isMedium()) {
+ dialogWidth = '500px';
+ }
+
this.dialogService.open(CreateDeveloperAppComponent, {
- width: '448px',
+ width: dialogWidth,
focusOnShow: false,
header: 'Create Developer App',
closeOnEscape: true,
From 1c9c7aa6876e7e2fa9f8aa8e1c3782250c64d726 Mon Sep 17 00:00:00 2001
From: Roma
Date: Fri, 21 Mar 2025 12:00:45 +0200
Subject: [PATCH 12/14] style(developer-apps): Fixed styles so apps list takes
full height
---
.../developer-apps-container.component.html | 4 +-
.../developer-apps-container.component.scss | 6 ++
.../developer-apps-list.component.scss | 60 ++++++++++---------
3 files changed, 42 insertions(+), 28 deletions(-)
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.html b/src/app/features/settings/developer-apps/developer-apps-container.component.html
index 622c11cec..17a12df66 100644
--- a/src/app/features/settings/developer-apps/developer-apps-container.component.html
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.html
@@ -6,4 +6,6 @@
(buttonClick)="createDeveloperApp()"
/>
-
+
diff --git a/src/app/features/settings/developer-apps/developer-apps-container.component.scss b/src/app/features/settings/developer-apps/developer-apps-container.component.scss
index 43b3dda99..3a0294d96 100644
--- a/src/app/features/settings/developer-apps/developer-apps-container.component.scss
+++ b/src/app/features/settings/developer-apps/developer-apps-container.component.scss
@@ -3,4 +3,10 @@
:host {
@include mix.flex-column;
+ flex: 1;
+
+ section {
+ @include mix.flex-column;
+ flex: 1;
+ }
}
diff --git a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
index e327dbce6..13e3d1ff1 100644
--- a/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
+++ b/src/app/features/settings/developer-apps/developer-apps-list/developer-apps-list.component.scss
@@ -1,42 +1,48 @@
@use "assets/styles/variables" as var;
@use "assets/styles/mixins" as mix;
-.content-container {
- padding: 1.7rem;
- color: var.$dark-blue-1;
- background-color: var.$white;
+:host {
+ @include mix.flex-column;
+ flex: 1;
+
+ .content-container {
+ flex: 1;
+ padding: 1.7rem;
+ color: var.$dark-blue-1;
+ background-color: var.$white;
+
+ &.mobile {
+ padding: 1rem;
+ }
- &.mobile {
- padding: 1rem;
- }
+ p {
+ margin-bottom: 1.7rem;
+ }
- p {
- margin-bottom: 1.7rem;
- }
+ .applications-container {
+ @include mix.flex-column;
+ gap: 0.85rem;
- .applications-container {
- @include mix.flex-column;
- gap: 0.85rem;
+ p-card {
+ .card-body {
+ &.mobile {
+ @include mix.flex-column;
+ gap: 0.85rem;
- p-card {
- .card-body {
- &.mobile {
- @include mix.flex-column;
- gap: 0.85rem;
+ a {
+ align-self: flex-start;
+ }
- a {
- align-self: flex-start;
+ .button-container {
+ align-self: flex-end;
+ width: 50%;
+ }
}
- .button-container {
- align-self: flex-end;
- width: 50%;
+ &:not(.mobile) {
+ @include mix.flex-center-between;
}
}
-
- &:not(.mobile) {
- @include mix.flex-center-between;
- }
}
}
}
From 5e32efb59426b95de80677eaddd3a143096cd046 Mon Sep 17 00:00:00 2001
From: Roma
Date: Fri, 21 Mar 2025 12:37:56 +0200
Subject: [PATCH 13/14] feat(developer-apps): Added notification when client
secret or id is copied
---
.../developer-app-details.component.html | 62 ++++++++++++-------
.../developer-app-details.component.scss | 29 +++++++++
.../developer-app-details.component.ts | 27 ++++++--
3 files changed, 90 insertions(+), 28 deletions(-)
diff --git a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
index b888610fd..f229fbbfc 100644
--- a/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
+++ b/src/app/features/settings/developer-apps/developer-app-details/developer-app-details.component.html
@@ -26,15 +26,23 @@ Client ID
share publicly.
-
-
-
+
-
-
-
+ Copied!
+
+
+
+
+
+
+
+
@@ -48,21 +56,31 @@ Client Secret
-
-
-
+
-
-
-
+ Copied!
+
+
+
+
+
+
+
+
(null);
@@ -70,11 +69,15 @@ export class DeveloperAppDetailsComponent implements OnInit {
clientSecret = signal(
'clientsecretclientsecretclientsecretclientsecret',
);
- clientId = signal('clientid');
hiddenClientSecret = computed(() =>
'*'.repeat(this.clientSecret().length),
);
+ clientSecretCopiedNotificationVisible = signal(false);
+
+ clientId = signal('clientid');
+ clientIdCopiedNotificationVisible = signal(false);
+ readonly DeveloperAppFormFormControls = DeveloperAppFormFormControls;
readonly editAppForm: DeveloperAppForm = new FormGroup({
[DeveloperAppFormFormControls.AppName]: new FormControl(
this.developerApp().appName,
@@ -146,11 +149,23 @@ export class DeveloperAppDetailsComponent implements OnInit {
}
clientIdCopiedToClipboard(): void {
- //TODO maybe show message
+ this.clientIdCopiedNotificationVisible.set(true);
+
+ timer(2500)
+ .pipe(takeUntilDestroyed(this.destroyRef))
+ .subscribe(() => {
+ this.clientIdCopiedNotificationVisible.set(false);
+ });
}
clientSecretCopiedToClipboard(): void {
- //TODO maybe show message
+ this.clientSecretCopiedNotificationVisible.set(true);
+
+ timer(2500)
+ .pipe(takeUntilDestroyed(this.destroyRef))
+ .subscribe(() => {
+ this.clientSecretCopiedNotificationVisible.set(false);
+ });
}
submitForm(): void {
From 6247699aa1124915bff90718297377082257f83d Mon Sep 17 00:00:00 2001
From: Roma
Date: Fri, 21 Mar 2025 12:41:09 +0200
Subject: [PATCH 14/14] fix(styles): Fix after merging main
---
src/assets/styles/styles.scss | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/assets/styles/styles.scss b/src/assets/styles/styles.scss
index 61d3ff4a2..10e18939d 100644
--- a/src/assets/styles/styles.scss
+++ b/src/assets/styles/styles.scss
@@ -17,7 +17,6 @@
@use "./overrides/radio";
@use "./overrides/dropdown";
@use "./overrides/confirmation-dialog";
-@use "./overrides/tabs";
@use "./overrides/iconfield";
@layer base, primeng, reset;