add teanant apps list
This commit is contained in:
parent
5a0ffcc73b
commit
7abcdcf8f1
@ -0,0 +1,5 @@
|
||||
export interface AppListDto {
|
||||
id: string;
|
||||
name: string;
|
||||
visibility: string;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {lastValueFrom, Observable} from "rxjs";
|
||||
import {PalantirService} from '../palantir.service';
|
||||
import {SubjectListDto} from './dtos/subject-list-dto';
|
||||
import {SubjectListDto} from '../dtos/subject-list-dto';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {lastValueFrom, Observable, of} from "rxjs";
|
||||
import {PalantirService} from '../palantir.service';
|
||||
import {TenantGridViewDto} from './dtos/tenant-grid-view-dto';
|
||||
import {AppListDto} from '../dtos/app-list-dto';
|
||||
import {TenantGridViewDto} from '../dtos/tenant-grid-view-dto';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -30,4 +31,12 @@ export class TenantService extends PalantirService {
|
||||
getTenantAsync(id: string | null, onError?: (error: any) => void): Promise<TenantGridViewDto | null> {
|
||||
return lastValueFrom(this.getTenant$(id, onError));
|
||||
}
|
||||
|
||||
getTenantApps$(id: string, onError?: (error: any) => void): Observable<AppListDto[]> {
|
||||
return this.handleRequest(this.http.get<AppListDto[]>(this.baseUrl + `/${id}/apps`), onError);
|
||||
}
|
||||
|
||||
getTenantAppsAsync(id: string, onError?: (error: any) => void): Promise<AppListDto[]> {
|
||||
return lastValueFrom(this.getTenantApps$(id, onError));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
@if (loading()) {
|
||||
Loading...
|
||||
} @else {
|
||||
@for (app of apps(); track app.id) {
|
||||
<app-panel class="neutral-80">
|
||||
<span class="title">{{app.name}}</span>
|
||||
<span class="actions">
|
||||
<button [routerLink]="'app/' + app.id" class="primary outline">View Details</button>
|
||||
</span>
|
||||
</app-panel>
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .5rem;
|
||||
|
||||
app-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AppListComponent } from './app-list.component';
|
||||
|
||||
describe('AppListComponent', () => {
|
||||
let component: AppListComponent;
|
||||
let fixture: ComponentFixture<AppListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AppListComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AppListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,36 @@
|
||||
import {Component, inject, input, OnInit, signal} from '@angular/core';
|
||||
import {AppListDto} from '../../../clients/gandalf/mithrandir/dtos/app-list-dto';
|
||||
import {TenantService} from '../../../clients/gandalf/mithrandir/tenant/tenant.service';
|
||||
import {PanelComponent} from '../../panel/panel.component';
|
||||
import {RouterLink} from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-app-list',
|
||||
imports: [
|
||||
PanelComponent,
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './app-list.component.html',
|
||||
styleUrl: './app-list.component.scss',
|
||||
})
|
||||
export class AppListComponent implements OnInit {
|
||||
|
||||
public tenantId = input<string>()
|
||||
|
||||
protected loading = signal<boolean>(true);
|
||||
protected apps = signal<AppListDto[]>([]);
|
||||
|
||||
private tenantService = inject(TenantService);
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
|
||||
const tenantId = this.tenantId();
|
||||
|
||||
if (tenantId) {
|
||||
const apps = await this.tenantService.getTenantAppsAsync(tenantId);
|
||||
this.apps.set(apps);
|
||||
this.loading.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,7 +3,7 @@ import {PanelComponent} from '../../panel/panel.component';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {NgClass} from '@angular/common';
|
||||
import {SubjectService} from '../../../clients/gandalf/mithrandir/subject/subject.service';
|
||||
import {SubjectListDto} from '../../../clients/gandalf/mithrandir/subject/dtos/subject-list-dto';
|
||||
import {SubjectListDto} from '../../../clients/gandalf/mithrandir/dtos/subject-list-dto';
|
||||
|
||||
@Component({
|
||||
selector: 'app-subject-list',
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
</ng-template>
|
||||
|
||||
<ng-template tabId="apps" let-tab>
|
||||
{{tab.name}} - content
|
||||
<app-app-list [tenantId]="tenantId()!"></app-app-list>
|
||||
</ng-template>
|
||||
|
||||
<ng-template tabId="groups" let-tab>
|
||||
|
||||
@ -3,13 +3,15 @@ import {TabGroup, TabGroupComponent} from '../../tab-group/tab-group.component';
|
||||
import {ActiveTabDirective} from '../../tab-group/active-tab.directive';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {SubjectListComponent} from '../../subject/subject-list/subject-list.component';
|
||||
import {AppListComponent} from '../../app/app-list/app-list.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tenant-detail',
|
||||
imports: [
|
||||
TabGroupComponent,
|
||||
ActiveTabDirective,
|
||||
SubjectListComponent
|
||||
SubjectListComponent,
|
||||
AppListComponent
|
||||
],
|
||||
templateUrl: './tenant-detail.component.html',
|
||||
styleUrl: './tenant-detail.component.scss',
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import {Component, inject, OnInit, signal} from '@angular/core';
|
||||
import {TenantService} from '../../../clients/gandalf/mithrandir/tenant/tenant.service';
|
||||
import {TenantGridViewDto} from '../../../clients/gandalf/mithrandir/tenant/dtos/tenant-grid-view-dto';
|
||||
import {PanelComponent} from '../../panel/panel.component';
|
||||
import {LinkComponent} from '../../link/link.component';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {NgClass} from '@angular/common';
|
||||
import {TenantGridViewDto} from '../../../clients/gandalf/mithrandir/dtos/tenant-grid-view-dto';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tenant-grid',
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import {ResolveFn} from "@angular/router";
|
||||
import {TenantGridViewDto} from "../clients/gandalf/mithrandir/tenant/dtos/tenant-grid-view-dto";
|
||||
import {inject} from "@angular/core";
|
||||
import {TenantService} from "../clients/gandalf/mithrandir/tenant/tenant.service";
|
||||
import {map} from 'rxjs';
|
||||
import {TenantGridViewDto} from '../clients/gandalf/mithrandir/dtos/tenant-grid-view-dto';
|
||||
|
||||
export const tenantResolver: ResolveFn<TenantGridViewDto | null> = (route, state) => {
|
||||
const tenantService = inject(TenantService);
|
||||
|
||||
@ -4,7 +4,9 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Suspectus.Gandalf.Palantir.Abstractions;
|
||||
using Suspectus.Gandalf.Palantir.Data.Database;
|
||||
using Suspectus.Gandalf.Palantir.Data.Dto.App;
|
||||
using Suspectus.Gandalf.Palantir.Data.Dto.Tenant;
|
||||
using Suspectus.Gandalf.Palantir.Data.Entities.Base;
|
||||
|
||||
namespace Suspectus.Gandalf.Palantir.Api.Controllers;
|
||||
|
||||
@ -21,7 +23,7 @@ public class TenantController : ControllerBase
|
||||
_context = context;
|
||||
_hashids = hashids;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Get(InvokerContext invokerContext, CancellationToken cancellationToken)
|
||||
{
|
||||
@ -29,7 +31,7 @@ public class TenantController : ControllerBase
|
||||
.Where(x => x.Id!.Value == invokerContext.Invoker!.SubjectId)
|
||||
.SelectMany(x => x.Tenants)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
|
||||
var dtos = tenantEntities.Select(x => new TenantGridViewDto
|
||||
{
|
||||
Id = _hashids.EncodeLong(x.Id!.Value),
|
||||
@ -41,23 +43,26 @@ public class TenantController : ControllerBase
|
||||
});
|
||||
return Ok(dtos);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{idHash}")]
|
||||
public async Task<IActionResult> Get(CancellationToken cancellationToken, string idHash, InvokerContext invokerContext)
|
||||
public async Task<IActionResult> Get(CancellationToken cancellationToken, string idHash,
|
||||
InvokerContext invokerContext)
|
||||
{
|
||||
if (!_hashids.TryDecodeSingleLong(idHash, out var id))
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
|
||||
var tenant = await _context.Tenants.SingleOrDefaultAsync(x => x.Id == id, cancellationToken);
|
||||
|
||||
|
||||
if (tenant is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var userHasRelation = await _context.TenantSubjectRelations.AnyAsync(x => x.SubjectId == invokerContext.Invoker!.SubjectId && x.TenantId == id, cancellationToken: cancellationToken);
|
||||
|
||||
var userHasRelation = await _context.TenantSubjectRelations.AnyAsync(
|
||||
x => x.SubjectId == invokerContext.Invoker!.SubjectId && x.TenantId == id,
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
if (!userHasRelation)
|
||||
{
|
||||
@ -73,7 +78,47 @@ public class TenantController : ControllerBase
|
||||
OwnerId = _hashids.EncodeLong(tenant.OwnerId),
|
||||
Visibility = tenant.Visibility
|
||||
};
|
||||
|
||||
|
||||
return Ok(dto);
|
||||
}
|
||||
|
||||
[HttpGet("{tenantIdHash}/apps")]
|
||||
public async Task<IActionResult> GetTenantApps(InvokerContext invokerContext, string tenantIdHash,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (!_hashids.TryDecodeSingleLong(tenantIdHash, out var tenantId))
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var tenantExists = await _context.Tenants.AnyAsync(x => x.Id == tenantId, cancellationToken);
|
||||
|
||||
if (!tenantExists)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var relationExists = await _context.TenantSubjectRelations
|
||||
.AnyAsync(x => x.SubjectId == invokerContext.Invoker!.SubjectId, cancellationToken);
|
||||
|
||||
if (!relationExists)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
var apps = await _context.AppSubjectRelations
|
||||
.Where(x => x.SubjectId == invokerContext.Invoker!.SubjectId)
|
||||
.Where(x => x.App!.TenantId == tenantId)
|
||||
.Select(x => x.App!)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var dtos = apps.Select(x => new AppListDto
|
||||
{
|
||||
Id = _hashids.EncodeLong(x.Id!.Value),
|
||||
Name = x.Name,
|
||||
Visibility = x.Visibility
|
||||
});
|
||||
|
||||
return Ok(dtos);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
using Suspectus.Gandalf.Palantir.Data.Entities.Base;
|
||||
|
||||
namespace Suspectus.Gandalf.Palantir.Data.Dto.App;
|
||||
|
||||
public class AppListDto
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required EntityVisibility Visibility { get; set; }
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user