+
+
+
+ Admin priveleges
+
+
diff --git a/src/app/auth/settings/account-settings.component.scss b/src/app/auth/settings/account-settings.component.scss
index fc16e95c4..d3d25c658 100644
--- a/src/app/auth/settings/account-settings.component.scss
+++ b/src/app/auth/settings/account-settings.component.scss
@@ -1,5 +1,21 @@
@import "var";
+:host {
+ ::ng-deep {
+ .mat-slide-toggle {
+ .mat-slide-toggle-ripple {
+ position: relative;
+ }
+ }
+
+ .mdc-switch {
+ .mdc-switch__ripple {
+ display: none;
+ }
+ }
+ }
+}
+
.p-responsive {
padding: 0 60px;
diff --git a/src/app/auth/settings/account-settings.component.ts b/src/app/auth/settings/account-settings.component.ts
index e0e20860f..b7c3f27b3 100644
--- a/src/app/auth/settings/account-settings.component.ts
+++ b/src/app/auth/settings/account-settings.component.ts
@@ -3,13 +3,14 @@ import { AccountFragment } from "src/app/api/kamu.graphql.interface";
import { AccountSettingsTabs } from "./account-settings.constants";
import { ChangeDetectionStrategy, Component, inject, OnInit } from "@angular/core";
import { ActivatedRoute, NavigationEnd, Router } from "@angular/router";
-import { filter } from "rxjs/operators";
+import { filter, map } from "rxjs/operators";
import { BaseComponent } from "src/app/common/base.component";
import AppValues from "src/app/common/app.values";
import { MaybeNull, MaybeUndefined } from "src/app/common/app.types";
-import { Observable } from "rxjs";
-import { LoggedUserService } from "../logged-user.service";
+import { combineLatest, Observable } from "rxjs";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
+import { MatSlideToggleChange } from "@angular/material/slide-toggle";
+import { LocalStorageService } from "src/app/services/local-storage.service";
@Component({
selector: "app-settings",
@@ -26,7 +27,12 @@ export class AccountSettingsComponent extends BaseComponent implements OnInit {
private router = inject(Router);
private route = inject(ActivatedRoute);
- private loggedUserService = inject(LoggedUserService);
+ private localStorageService = inject(LocalStorageService);
+
+ public userData$: Observable<{
+ user: AccountFragment;
+ adminPrivileges: boolean;
+ } | null>;
public ngOnInit(): void {
this.router.events
@@ -39,13 +45,35 @@ export class AccountSettingsComponent extends BaseComponent implements OnInit {
});
this.extractActiveTabFromRoute();
- this.user$ = this.loggedUserService.loggedInUserChanges;
+
+ this.userData$ = combineLatest([
+ this.loggedUserService.loggedInUserChanges,
+ this.loggedUserService.adminPrivilegesChanges,
+ ]).pipe(
+ map(([user, adminPrivileges]) => {
+ return user
+ ? {
+ user,
+ adminPrivileges: adminPrivileges.value,
+ }
+ : null;
+ }),
+ );
}
public getRouteLink(tab: AccountSettingsTabs): string {
return `/${ProjectLinks.URL_SETTINGS}/${tab}`;
}
+ public get isAdmin(): boolean {
+ return this.loggedUserService.isAdmin;
+ }
+
+ public adminSlideToggleChange(event: MatSlideToggleChange): void {
+ this.loggedUserService.emitAdminPrivilegesChanges(event.checked);
+ this.localStorageService.setAdminPriveleges(event.checked);
+ }
+
private extractActiveTabFromRoute(): void {
const categoryParam: MaybeUndefined
= this.route.snapshot.params[
ProjectLinks.URL_PARAM_CATEGORY
diff --git a/src/app/common/app.types.ts b/src/app/common/app.types.ts
index a43eec10a..c03b27e34 100644
--- a/src/app/common/app.types.ts
+++ b/src/app/common/app.types.ts
@@ -1,3 +1,14 @@
export type MaybeNull = T | null;
export type MaybeUndefined = T | undefined;
export type MaybeNullOrUndefined = T | null | undefined;
+
+export interface AdminAvailableButtonType {
+ label: string;
+ icon: string;
+ datasetId: string;
+ visible?: boolean;
+ showAdminIcon?: boolean;
+ adminPrivileges?: boolean;
+ disabled?: boolean;
+ class?: string;
+}
diff --git a/src/app/common/app.values.ts b/src/app/common/app.values.ts
index ab41e3817..1e70737cb 100644
--- a/src/app/common/app.values.ts
+++ b/src/app/common/app.values.ts
@@ -8,6 +8,8 @@ export default class AppValues {
public static readonly LOCAL_STORAGE_LOGIN_CALLBACK_URL = "login_callback_url";
public static readonly LOCAL_STORAGE_LOGIN_REDIRECT_URL = "login_redirect_url";
public static readonly LOCAL_STORAGE_ACCOUNT_ID = "account_id";
+ public static readonly LOCAL_STORAGE_ADMIN_PRIVILEGES = "admin_priveleges";
+
public static readonly SESSION_STORAGE_SIDE_PANEL_VISIBLE = "side_panel_visible";
public static readonly DEFAULT_USER_DISPLAY_NAME = "anonymous";
public static readonly DEFAULT_AVATAR_URL = "https://avatars.githubusercontent.com/u/11951648?v=4";
diff --git a/src/app/common/base.component.ts b/src/app/common/base.component.ts
index 964617044..3027747d2 100644
--- a/src/app/common/base.component.ts
+++ b/src/app/common/base.component.ts
@@ -5,9 +5,12 @@ import ProjectLinks from "../project-links";
import { requireValue } from "./app.helpers";
import { UnsubscribeDestroyRefAdapter } from "./unsubscribe.ondestroy.adapter";
import { Observable, map } from "rxjs";
+import { LoggedUserService } from "../auth/logged-user.service";
export abstract class BaseComponent extends UnsubscribeDestroyRefAdapter {
+ public adminPrivileges$: Observable<{ value: boolean }>;
protected activatedRoute = inject(ActivatedRoute);
+ protected loggedUserService = inject(LoggedUserService);
public get searchString(): string {
return window.location.search;
diff --git a/src/app/common/components/admin-available-button/admin-available-button.component.html b/src/app/common/components/admin-available-button/admin-available-button.component.html
new file mode 100644
index 000000000..5e7cdbbc1
--- /dev/null
+++ b/src/app/common/components/admin-available-button/admin-available-button.component.html
@@ -0,0 +1,5 @@
+
diff --git a/src/app/common/components/admin-available-button/admin-available-button.component.scss b/src/app/common/components/admin-available-button/admin-available-button.component.scss
new file mode 100644
index 000000000..d7f8faa6c
--- /dev/null
+++ b/src/app/common/components/admin-available-button/admin-available-button.component.scss
@@ -0,0 +1,7 @@
+mat-icon.admin-icon {
+ color: #378bb0;
+ transform: scale(0.65);
+ position: relative;
+ bottom: 4px;
+ right: 6px;
+}
diff --git a/src/app/common/components/admin-available-button/admin-available-button.component.spec.ts b/src/app/common/components/admin-available-button/admin-available-button.component.spec.ts
new file mode 100644
index 000000000..4a5369373
--- /dev/null
+++ b/src/app/common/components/admin-available-button/admin-available-button.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AdminAvailableButtonComponent } from './admin-available-button.component';
+
+describe('AdminAvailableButtonComponent', () => {
+ let component: AdminAvailableButtonComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [AdminAvailableButtonComponent]
+ });
+ fixture = TestBed.createComponent(AdminAvailableButtonComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/common/components/admin-available-button/admin-available-button.component.ts b/src/app/common/components/admin-available-button/admin-available-button.component.ts
new file mode 100644
index 000000000..ab9e81283
--- /dev/null
+++ b/src/app/common/components/admin-available-button/admin-available-button.component.ts
@@ -0,0 +1,23 @@
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from "@angular/core";
+
+@Component({
+ selector: "app-admin-available-button",
+ templateUrl: "./admin-available-button.component.html",
+ styleUrls: ["./admin-available-button.component.scss"],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AdminAvailableButtonComponent {
+ @Input() public visible: boolean = true;
+ @Input() public icon: string = "";
+ @Input({ required: true }) public label: string;
+ @Input() public class?: string;
+ @Input() public disabled: boolean;
+ @Input() public datasetId: string;
+ @Input() public showAdwinIcon: boolean;
+ @Input() public adminPrivileges: boolean;
+ @Output() public onClick = new EventEmitter();
+
+ public click(): void {
+ this.onClick.emit();
+ }
+}
diff --git a/src/app/components/app-header/app-header.component.html b/src/app/components/app-header/app-header.component.html
index f830c269e..a7103fd13 100644
--- a/src/app/components/app-header/app-header.component.html
+++ b/src/app/components/app-header/app-header.component.html
@@ -88,7 +88,7 @@
class="d-flex flex-column align-items-center flex-md-row flex-self-stretch flex-md-self-auto width-full justify-content-between"
aria-label="Global"
>
-