Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: list resource templates #821

Merged
merged 18 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions AMW_angular/io/src/app/resource/resource-template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface ResourceTemplate {
id: number;
relatedResourceIdentifier: string;
name: string;
targetPath: string;
targetPlatforms: string[];
fileContent: string;
sourceType?: 'RESOURCE' | 'RESOURCE_TYPE';
}
55 changes: 55 additions & 0 deletions AMW_angular/io/src/app/resource/resource-templates.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ResourceTemplate } from './resource-template';
import { catchError, shareReplay, switchMap } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';
import { BaseService } from '../base/base.service';
import { toSignal } from '@angular/core/rxjs-interop';

@Injectable({ providedIn: 'root' })
export class ResourceTemplatesService extends BaseService {
private templates$: Subject<number> = new Subject<number>();
private templatesForType$: Subject<number> = new Subject<number>();

private templateById$: Observable<ResourceTemplate[]> = this.templates$.pipe(
switchMap((id: number) => this.getResourceTemplates(id)),
shareReplay(1),
);

private templateByTypeId$: Observable<ResourceTemplate[]> = this.templatesForType$.pipe(
switchMap((id: number) => this.getResourceTypeTemplates(id)),
shareReplay(1),
);

resourceTemplates = toSignal(this.templateById$, { initialValue: [] });

resourceTypeTemplates = toSignal(this.templateByTypeId$, { initialValue: [] });

constructor(private http: HttpClient) {
super();
}

setIdForResourceTemplateList(id: number) {
this.templates$.next(id);
}

setIdForResourceTypeTemplateList(id: number) {
this.templatesForType$.next(id);
}

getResourceTemplates(id: number): Observable<ResourceTemplate[]> {
return this.http
.get<ResourceTemplate[]>(`${this.getBaseUrl()}/resources/templates/${id}`, {
headers: this.getHeaders(),
})
.pipe(catchError(this.handleError));
}

getResourceTypeTemplates(id: number): Observable<ResourceTemplate[]> {
return this.http
.get<ResourceTemplate[]>(`${this.getBaseUrl()}/resources/templates/resourceType/${id}`, {
headers: this.getHeaders(),
})
.pipe(catchError(this.handleError));
}
}
2 changes: 1 addition & 1 deletion AMW_angular/io/src/app/resource/resource-types.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ResourceTypeRequest } from './resource-type-request';
@Injectable({ providedIn: 'root' })
export class ResourceTypesService extends BaseService {
private reload$ = new Subject<ResourceType[]>();
private resourceTypeId$: Subject<Number> = new Subject<Number>();
private resourceTypeId$: Subject<number> = new Subject<number>();
private predefinedResourceTypes$ = this.getPredefinedResourceTypes();

private rootResourceTypes$ = this.reload$.pipe(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,14 @@
<div class="page-content">
@if ((this.resource()?.name && !permissions().canEditResource)) {
<div class="container">
<span class="text-warning-2">Not Authorized! You are not allowed to Edit-Resources.</span>
<span class="text-warning-2">Not Authorized! You are not allowed to edit resources.</span>
</div>
} @else if (id() === 0) {
<div class="container">
<span>Please provide a resource-id to edit a resource.</span>
<span>Please provide the resource id to edit a resource.</span>
</div>
} @else {
<app-tile-component
[title]="'Templates'"
[actionName]="'New Template'"
[canAction]="true"
[isVisible]="false"
[lists]="templatesData()"
(tileAction)="add()"
(listAction)="doListAction($event)"
></app-tile-component>
<app-resource-templates-list [resource]="resource()" [contextId]="contextId()"></app-resource-templates-list>
<app-resource-functions-list [resource]="resource()" [contextId]="contextId()"></app-resource-functions-list>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
import { Component, computed, inject, Signal, signal } from '@angular/core';
import { Component, computed, inject, Signal } from '@angular/core';
import { LoadingIndicatorComponent } from '../../shared/elements/loading-indicator.component';
import { PageComponent } from '../../layout/page/page.component';
import { ActivatedRoute } from '@angular/router';
import { map } from 'rxjs/operators';
import { toSignal } from '@angular/core/rxjs-interop';
import { ResourceService } from '../../resource/resource.service';
import { Resource } from '../../resource/resource';
import { EntryAction, TileListEntry, TileListEntryOutput } from '../../shared/tile/tile-list/tile-list.component';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TileComponent } from '../../shared/tile/tile.component';
import { AuthService } from '../../auth/auth.service';
import { ResourceFunctionsListComponent } from './resource-functions/resource-functions-list.component';
import { ResourceTemplatesListComponent } from './resource-templates/resource-templates-list.component';

@Component({
selector: 'app-resource-edit',
standalone: true,
imports: [LoadingIndicatorComponent, PageComponent, TileComponent, ResourceFunctionsListComponent],
imports: [
LoadingIndicatorComponent,
PageComponent,
TileComponent,
ResourceFunctionsListComponent,
ResourceTemplatesListComponent,
],
templateUrl: './resource-edit.component.html',
})
export class ResourceEditComponent {
private authService = inject(AuthService);
private modalService = inject(NgbModal);
private resourceService = inject(ResourceService);
private route = inject(ActivatedRoute);

Expand All @@ -44,51 +48,4 @@ export class ResourceEditComponent {
return { canEditResource: false };
}
});

templatesData = signal([
{
title: 'Instance Templates',
entries: [
{ name: 'startJob_0.sh', description: 'startJob_0.sh', id: 0 },
{ name: 'startJob_1.sh', description: 'job 2 again', id: 1 },
] as TileListEntry[],
canEdit: true,
canDelete: true,
},
{
title: 'Resource Type Templates',
entries: [{ name: 'seg', description: 'segmentation', id: 666 }] as TileListEntry[],
canOverwrite: false,
},
]);

add() {
this.modalService.open('This would open a modal to add something');
}

doListAction($event: TileListEntryOutput) {
switch ($event.action) {
case EntryAction.edit:
this.edit($event.id);
return;
case EntryAction.delete:
this.delete($event.id);
return;
case EntryAction.overwrite:
this.overwrite($event.id);
return;
}
}

private edit(id: number) {
this.modalService.open('This would open a modal to edit with id:' + id);
}

private delete(id: number) {
this.modalService.open('This would open a modal to delete with id:' + id);
}

private overwrite(id: number) {
this.modalService.open('This would open a modal to overwrite with id:' + id);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<app-loading-indicator [isLoading]="isLoading()"></app-loading-indicator>
<app-tile-component
[title]="'Functions'"
[actionName]="'New function'"
[actionName]="'New Function'"
[canAction]="permissions().canAdd"
[lists]="functionsData()"
(tileAction)="add()"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<app-loading-indicator [isLoading]="isLoading()"></app-loading-indicator>
<app-tile-component
[title]="'Templates'"
[actionName]="'New Template'"
[canAction]="permissions().canAdd"
[lists]="templatesData()"
(tileAction)="addTemplate()"
(listAction)="doListAction($event)"
></app-tile-component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { InputSignal, signal } from '@angular/core';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { ResourceTemplatesListComponent } from './resource-templates-list.component';
import { Resource } from '../../../resource/resource';

describe('ResourceTemplatesComponent', () => {
let component: ResourceTemplatesListComponent;
let fixture: ComponentFixture<ResourceTemplatesListComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ResourceTemplatesListComponent],
providers: [provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()],
}).compileComponents();

fixture = TestBed.createComponent(ResourceTemplatesListComponent);
component = fixture.componentInstance;
component.resource = signal<Resource>(null) as unknown as InputSignal<Resource>;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Component, computed, inject, input, OnDestroy } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { LoadingIndicatorComponent } from '../../../shared/elements/loading-indicator.component';
import { TileComponent } from '../../../shared/tile/tile.component';
import { EntryAction, TileListEntryOutput } from '../../../shared/tile/tile-list/tile-list.component';
import { Action, AuthService } from '../../../auth/auth.service';
import { Resource } from '../../../resource/resource';
import { Subject } from 'rxjs';
import { ResourceTemplatesService } from '../../../resource/resource-templates.service';
import { ResourceTemplate } from '../../../resource/resource-template';

const RESOURCE_PERM = 'RESOURCE_TEMPLATE';
const RESOURCETYPE_PERM = 'RESOURCETYPE_TEMPLATE';

@Component({
selector: 'app-resource-templates-list',
standalone: true,
imports: [LoadingIndicatorComponent, TileComponent],
templateUrl: './resource-templates-list.component.html',
})
export class ResourceTemplatesListComponent implements OnDestroy {
private authService = inject(AuthService);
private modalService = inject(NgbModal);
private templatesService = inject(ResourceTemplatesService);
private destroy$ = new Subject<void>();

resource = input.required<Resource>();
contextId = input.required<number>();
templates = this.templatesService.resourceTemplates;

isLoading = computed(() => {
if (this.resource() != null) {
this.templatesService.setIdForResourceTemplateList(this.resource().id);
return false;
}
});

permissions = computed(() => {
if (this.authService.restrictions().length > 0 && this.resource()) {
return {
canShowInstanceTemplates: this.authService.hasPermission(RESOURCE_PERM, Action.READ),
canShowTypeTemplates: this.authService.hasPermission(RESOURCETYPE_PERM, Action.READ),
canAdd:
(this.contextId() === 1 || this.contextId === null) &&
this.authService.hasResourceGroupPermission(RESOURCE_PERM, Action.CREATE, this.resource().resourceGroupId),
canEdit:
(this.contextId() === 1 || this.contextId === null) &&
this.authService.hasResourceGroupPermission(RESOURCE_PERM, Action.UPDATE, this.resource().resourceGroupId),
canDelete:
(this.contextId() === 1 || this.contextId === null) &&
this.authService.hasResourceGroupPermission(RESOURCE_PERM, Action.DELETE, this.resource().resourceGroupId),
};
} else {
return {
canShowInstanceTemplates: false,
canShowTypeTemplates: false,
canAdd: false,
canEdit: false,
canDelete: false,
};
}
});

templatesData = computed(() => {
if (this.templates()?.length > 0) {
const instanceTemplates = this.mapListEntries(
this.templates().filter((template) => template.sourceType === 'RESOURCE'),
);
const typeTemplates = this.mapListEntries(
this.templates().filter((template) => template.sourceType === 'RESOURCE_TYPE'),
);

const result = [];
if (this.permissions().canShowInstanceTemplates) {
result.push({
title: 'Resource Instance Templates',
entries: instanceTemplates,
canEdit: this.permissions().canEdit,
canDelete: this.permissions().canDelete,
});
}
if (this.permissions().canShowTypeTemplates) {
result.push({
title: 'Resource Type Templates',
entries: typeTemplates,
canEdit: false,
canDelete: false,
});
}
return result;
} else return null;
});

ngOnDestroy(): void {
this.destroy$.next(undefined);
}

doListAction($event: TileListEntryOutput) {
switch ($event.action) {
case EntryAction.edit:
this.editTemplate($event.id);
return;
case EntryAction.delete:
this.deleteTemplate($event.id);
return;
}
}

mapListEntries(templates: ResourceTemplate[]) {
return templates.map((template) => ({
name: template.name,
description: template.targetPath,
id: template.id,
}));
}

addTemplate() {
this.modalService.open('This would open a modal to add a new instance template');
}

private editTemplate(id: number) {
this.modalService.open('This would open a modal to edit template with id: ' + id);
}

private deleteTemplate(id: number) {
this.modalService.open('This would open a modal to delete template with id: ' + id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { RevisionInformation } from '../shared/model/revisionInformation';
@Injectable({ providedIn: 'root' })
export class ResourceFunctionsService extends BaseService {
private path = `${this.getBaseUrl()}/resources`;
private functions$: Subject<Number> = new Subject<Number>();
private functionsForType$: Subject<Number> = new Subject<Number>();
private functions$: Subject<number> = new Subject<number>();
private functionsForType$: Subject<number> = new Subject<number>();

private functionById$: Observable<ResourceFunction[]> = this.functions$.pipe(
switchMap((id: number) => this.getResourceFunctions(id)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,10 @@
<span>Please provide a resourceType-id to edit a resource.</span>
</div>
} @else {
<app-tile-component
[title]="'Templates'"
[actionName]="'New Template'"
[canAction]="true"
[isVisible]="false"
[lists]="templatesData()"
(tileAction)="add()"
(listAction)="doListAction($event)"
></app-tile-component>
<app-resource-type-templates-list
[resourceType]="resourceType()"
[contextId]="contextId()"
></app-resource-type-templates-list>
<app-resource-type-functions-list
[resourceType]="resourceType()"
[contextId]="contextId()"
Expand Down
Loading
Loading