diff --git a/src/Turnierplan.App/Client/src/app/i18n/de.ts b/src/Turnierplan.App/Client/src/app/i18n/de.ts index 7cdc32f3..b18a4b32 100644 --- a/src/Turnierplan.App/Client/src/app/i18n/de.ts +++ b/src/Turnierplan.App/Client/src/app/i18n/de.ts @@ -1010,6 +1010,9 @@ export const de = { Views: 'Ansichten', Settings: 'Einstellungen' }, + ManageResources: { + EmptyGroup: 'Keine Einträge vorhanden' + }, Settings: { Rename: { Button: 'Umbenennen', diff --git a/src/Turnierplan.App/Client/src/app/portal/components/manage-resources/manage-resources.component.html b/src/Turnierplan.App/Client/src/app/portal/components/manage-resources/manage-resources.component.html new file mode 100644 index 00000000..4a40eeb4 --- /dev/null +++ b/src/Turnierplan.App/Client/src/app/portal/components/manage-resources/manage-resources.component.html @@ -0,0 +1,32 @@ +@if (viewModel) { +
+ @for (column of viewModel.columns; track $index) { +
+ @for (group of column.groups; track group.id) { +
+
{{ group.name }}
+
    + @for (resource of group.resources; track resource.id) { +
  • + @switch (resource.type) { + @case (resourceType.Commodity) { + + } + @case (resourceType.Personnel) { + + } + } + {{ resource.name }} +
  • + } @empty { +
  • + } +
+
+ } +
+ } +
+} diff --git a/src/Turnierplan.App/Client/src/app/portal/components/manage-resources/manage-resources.component.ts b/src/Turnierplan.App/Client/src/app/portal/components/manage-resources/manage-resources.component.ts new file mode 100644 index 00000000..8f826fa4 --- /dev/null +++ b/src/Turnierplan.App/Client/src/app/portal/components/manage-resources/manage-resources.component.ts @@ -0,0 +1,277 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { ResourcePlannerDto } from '../../../api/models/resource-planner-dto'; +import { ResourceGroupType } from '../../../api/models/resource-group-type'; +import { ResourceAssignmentState } from '../../../api/models/resource-assignment-state'; +import { ResourceType } from '../../../api/models/resource-type'; +import { TranslateDirective } from '@ngx-translate/core'; + +type ResourcesViewModel = { + columns: { + groups: { + id: number; + name: string; + description?: string; + type: ResourceGroupType; + range?: { + start: Date; + end: Date; + }; + resources: { + id: number; + type: ResourceType; + name: string; + notes?: string; + state: ResourceAssignmentState; + }[]; + }[]; + }[]; +}; + +@Component({ + selector: 'tp-manage-resources', + imports: [TranslateDirective], + templateUrl: './manage-resources.component.html' +}) +export class ManageResourcesComponent { + @Input() + public set resourcePlanner(value: ResourcePlannerDto) { + this._resourcePlanner = value; + this.updateViewModel(); + } + + @Output() + public errorOccured = new EventEmitter(); + + protected readonly resourceType = ResourceType; + + protected viewModel?: ResourcesViewModel; + private _resourcePlanner?: ResourcePlannerDto; + + private updateViewModel(): void { + // TODO: Convert resource planner to view model + + const time = (h: number, m: number) => { + return new Date(2026, 7, 29, h, m, 0); + }; + + let id = 1; + + const column = (k: number) => ({ + groups: [ + { + id: id++, + name: 'Ansprechperson', + type: ResourceGroupType.Workshift, + range: { + start: time(11, 30), + end: time(17, 30) + }, + resources: [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + } + ] + }, + { + id: id++, + name: 'Schicht 1', + type: ResourceGroupType.Workshift, + range: { + start: time(10, 0), + end: time(13, 0) + }, + resources: [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Requested + }, + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + }, + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + } + ] + }, + { + id: id++, + name: 'Schicht 2', + type: ResourceGroupType.Workshift, + range: { + start: time(13, 0), + end: time(16, 0) + }, + resources: [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Requested + }, + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + }, + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Proposed + } + ] + }, + { + id: id++, + name: 'Schicht 3', + type: ResourceGroupType.Workshift, + range: { + start: time(16, 0), + end: time(19, 0) + }, + resources: [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + }, + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + }, + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + } + ] + }, + { + id: id++, + name: 'Kuchen', + type: ResourceGroupType.General, + resources: [ + { + id: id++, + name: 'Quark Sahne Torte', + type: ResourceType.Commodity, + state: ResourceAssignmentState.Confirmed + }, + { + id: id++, + name: 'Käsekuchen', + type: ResourceType.Commodity, + state: ResourceAssignmentState.Confirmed + }, + { + id: id++, + name: 'Hasselnuss-Gugelhupf', + type: ResourceType.Commodity, + state: ResourceAssignmentState.Requested + } + ] + }, + { + id: id++, + name: 'Turnierleitung', + type: ResourceGroupType.General, + resources: + k == 3 + ? [] + : [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + } + ] + }, + { + id: id++, + name: 'Turnieraufsicht', + type: ResourceGroupType.General, + resources: [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + }, + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + } + ] + }, + { + id: id++, + name: 'Hallensprecher', + type: ResourceGroupType.General, + resources: [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + }, + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + } + ] + }, + { + id: id++, + name: 'Siegerehrung', + type: ResourceGroupType.General, + resources: [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + } + ] + }, + { + id: id++, + name: 'Sanitäter', + type: ResourceGroupType.General, + resources: [ + { + id: id++, + name: 'Max Mustermann', + type: ResourceType.Personnel, + state: ResourceAssignmentState.Confirmed + } + ] + } + ] + }); + + this.viewModel = { + columns: [column(0), column(1), column(2), column(3), column(4)] + }; + } +} diff --git a/src/Turnierplan.App/Client/src/app/portal/pages/view-resource-planner/view-resource-planner.component.html b/src/Turnierplan.App/Client/src/app/portal/pages/view-resource-planner/view-resource-planner.component.html index e2c665cd..7f893f47 100644 --- a/src/Turnierplan.App/Client/src/app/portal/pages/view-resource-planner/view-resource-planner.component.html +++ b/src/Turnierplan.App/Client/src/app/portal/pages/view-resource-planner/view-resource-planner.component.html @@ -18,16 +18,20 @@ } @case (2) { + @if (isUpdatingName) { + + } } } - + @if (currentPage !== 0) {
@switch (currentPage) { @@ -61,7 +65,15 @@ @if (currentPage === 0) { - resources +
+
+
+ +
+
+
}
diff --git a/src/Turnierplan.App/Client/src/app/portal/pages/view-resource-planner/view-resource-planner.component.ts b/src/Turnierplan.App/Client/src/app/portal/pages/view-resource-planner/view-resource-planner.component.ts index 4efae35b..bbfa0f40 100644 --- a/src/Turnierplan.App/Client/src/app/portal/pages/view-resource-planner/view-resource-planner.component.ts +++ b/src/Turnierplan.App/Client/src/app/portal/pages/view-resource-planner/view-resource-planner.component.ts @@ -4,7 +4,7 @@ import { Actions } from '../../../generated/actions'; import { ResourcePlannerDto } from '../../../api/models/resource-planner-dto'; import { LoadingState, LoadingStateDirective } from '../../directives/loading-state.directive'; import { of, Subject, switchMap, takeUntil } from 'rxjs'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { TurnierplanApi } from '../../../api/turnierplan-api'; import { TitleService } from '../../services/title.service'; import { getResourcePlanner } from '../../../api/fn/resource-planners/get-resource-planner'; @@ -12,6 +12,11 @@ import { RenameButtonComponent } from '../../components/rename-button/rename-but import { DeleteWidgetComponent } from '../../components/delete-widget/delete-widget.component'; import { IsActionAllowedDirective } from '../../directives/is-action-allowed.directive'; import { RbacWidgetComponent } from '../../components/rbac-widget/rbac-widget.component'; +import { setResourcePlannerName } from '../../../api/fn/resource-planners/set-resource-planner-name'; +import { SmallSpinnerComponent } from '../../../core/components/small-spinner/small-spinner.component'; +import { NotificationService } from '../../../core/services/notification.service'; +import { deleteResourcePlanner } from '../../../api/fn/resource-planners/delete-resource-planner'; +import { ManageResourcesComponent } from '../../components/manage-resources/manage-resources.component'; @Component({ imports: [ @@ -20,7 +25,9 @@ import { RbacWidgetComponent } from '../../components/rbac-widget/rbac-widget.co RenameButtonComponent, DeleteWidgetComponent, IsActionAllowedDirective, - RbacWidgetComponent + RbacWidgetComponent, + SmallSpinnerComponent, + ManageResourcesComponent ], templateUrl: './view-resource-planner.component.html' }) @@ -29,13 +36,14 @@ export class ViewResourcePlannerComponent { protected loadingState: LoadingState = { isLoading: true }; protected resourcePlanner?: ResourcePlannerDto; + protected isUpdatingName = false; protected currentPage = 0; protected pages: PageFrameNavigationTab[] = [ { id: 0, title: 'Portal.ViewResourcePlanner.Pages.Resources', - icon: 'bi-box-seam' + icon: 'bi-columns' }, { id: 1, @@ -55,7 +63,9 @@ export class ViewResourcePlannerComponent { constructor( private readonly turnierplanApi: TurnierplanApi, private readonly route: ActivatedRoute, - private readonly titleService: TitleService + private readonly router: Router, + private readonly titleService: TitleService, + private readonly notificationService: NotificationService ) {} public ngOnInit(): void { @@ -94,10 +104,45 @@ export class ViewResourcePlannerComponent { } protected renameResourcePlanner(name: string): void { - alert('Rename not implemented yet'); // TODO: Implement resource planner rename + if (!this.resourcePlanner || name === this.resourcePlanner.name || this.isUpdatingName) { + return; + } + + this.isUpdatingName = true; + + this.turnierplanApi.invoke(setResourcePlannerName, { id: this.resourcePlanner.id, body: { name: name } }).subscribe({ + next: () => { + if (this.resourcePlanner) { + this.resourcePlanner.name = name; + this.titleService.setTitleFrom(this.resourcePlanner); + } + this.isUpdatingName = false; + }, + error: (error) => { + this.loadingState = { isLoading: false, error: error }; + } + }); } protected deleteResourcePlanner(): void { - alert('Delete not implemented yet'); // TODO: Implement delete resource planner + if (!this.resourcePlanner) { + return; + } + + const organizationId = this.resourcePlanner.organizationId; + this.loadingState = { isLoading: true, error: undefined }; + this.turnierplanApi.invoke(deleteResourcePlanner, { id: this.resourcePlanner.id }).subscribe({ + next: () => { + this.notificationService.showNotification( + 'info', + 'Portal.ViewResourcePlanner.DeleteWidget.SuccessToast.Title', + 'Portal.ViewResourcePlanner.DeleteWidget.SuccessToast.Message' + ); + void this.router.navigate([`../../organization/${organizationId}`], { relativeTo: this.route }); + }, + error: (error) => { + this.loadingState = { isLoading: false, error: error }; + } + }); } } diff --git a/src/Turnierplan.App/Endpoints/ResourcePlanners/DeleteResourcePlannerEndpoint.cs b/src/Turnierplan.App/Endpoints/ResourcePlanners/DeleteResourcePlannerEndpoint.cs new file mode 100644 index 00000000..e21e84a2 --- /dev/null +++ b/src/Turnierplan.App/Endpoints/ResourcePlanners/DeleteResourcePlannerEndpoint.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Mvc; +using Turnierplan.App.Security; +using Turnierplan.Core.PublicId; +using Turnierplan.Dal.Repositories; + +namespace Turnierplan.App.Endpoints.ResourcePlanners; + +internal sealed class DeleteResourcePlannerEndpoint : EndpointBase +{ + protected override HttpMethod Method => HttpMethod.Delete; + + protected override string Route => "/api/resource-planners/{id}"; + + protected override Delegate Handler => Handle; + + private static async Task Handle( + [FromRoute] PublicId id, + IResourcePlannerRepository repository, + IAccessValidator accessValidator, + CancellationToken cancellationToken) + { + var resourcePlanner = await repository.GetByPublicIdAsync(id); + + if (resourcePlanner is null) + { + return Results.NotFound(); + } + + if (!accessValidator.IsActionAllowed(resourcePlanner, Actions.GenericWrite)) + { + return Results.Forbid(); + } + + repository.Remove(resourcePlanner); + + await repository.UnitOfWork.SaveChangesAsync(cancellationToken); + + return Results.NoContent(); + } +} diff --git a/src/Turnierplan.App/Endpoints/ResourcePlanners/SetResourcePlannerNameEndpoint.cs b/src/Turnierplan.App/Endpoints/ResourcePlanners/SetResourcePlannerNameEndpoint.cs new file mode 100644 index 00000000..cec8f1dc --- /dev/null +++ b/src/Turnierplan.App/Endpoints/ResourcePlanners/SetResourcePlannerNameEndpoint.cs @@ -0,0 +1,64 @@ +using FluentValidation; +using Microsoft.AspNetCore.Mvc; +using Turnierplan.App.Extensions; +using Turnierplan.App.Security; +using Turnierplan.Core.PublicId; +using Turnierplan.Dal.Repositories; + +namespace Turnierplan.App.Endpoints.ResourcePlanners; + +internal sealed class SetResourcePlannerNameEndpoint : EndpointBase +{ + protected override HttpMethod Method => HttpMethod.Patch; + + protected override string Route => "/api/resource-planners/{id}/name"; + + protected override Delegate Handler => Handle; + + private static async Task Handle( + [FromRoute] PublicId id, + [FromBody] SetResourcePlannerNameEndpointRequest request, + IResourcePlannerRepository repository, + IAccessValidator accessValidator, + CancellationToken cancellationToken) + { + if (!Validator.Instance.ValidateAndGetResult(request, out var result)) + { + return result; + } + + var resourcePlanner = await repository.GetByPublicIdAsync(id); + + if (resourcePlanner is null) + { + return Results.NotFound(); + } + + if (!accessValidator.IsActionAllowed(resourcePlanner, Actions.GenericWrite)) + { + return Results.Forbid(); + } + + resourcePlanner.Name = request.Name.Trim(); + + await repository.UnitOfWork.SaveChangesAsync(cancellationToken); + + return Results.NoContent(); + } + + public sealed record SetResourcePlannerNameEndpointRequest + { + public required string Name { get; init; } + } + + private sealed class Validator : AbstractValidator + { + public static readonly Validator Instance = new(); + + private Validator() + { + RuleFor(x => x.Name) + .NotEmpty(); + } + } +} diff --git a/src/Turnierplan.App/Mapping/Rules/ResourcePlannerMappingRule.cs b/src/Turnierplan.App/Mapping/Rules/ResourcePlannerMappingRule.cs index cc9e1ffb..8bc5acfc 100644 --- a/src/Turnierplan.App/Mapping/Rules/ResourcePlannerMappingRule.cs +++ b/src/Turnierplan.App/Mapping/Rules/ResourcePlannerMappingRule.cs @@ -34,8 +34,7 @@ protected override ResourcePlannerDto Map(IMapper mapper, MappingContext context { Id = group.Id, Name = group.Name, - Description = group.Description, - Type = group.Type, + Notes = group.Notes, Start = group.Start, End = group.End, Assignment = diff --git a/src/Turnierplan.App/Models/ResourceGroupDto.cs b/src/Turnierplan.App/Models/ResourceGroupDto.cs index 9d9ab26f..2a356ea1 100644 --- a/src/Turnierplan.App/Models/ResourceGroupDto.cs +++ b/src/Turnierplan.App/Models/ResourceGroupDto.cs @@ -6,11 +6,9 @@ public sealed record ResourceGroupDto { public required long Id { get; init; } - public required string? Name { get; init; } + public required string Name { get; init; } - public required string? Description { get; init; } - - public required ResourceGroupType Type { get; init; } + public required string? Notes { get; init; } public required DateTime? Start { get; init; } diff --git a/src/Turnierplan.Core/ResourcePlanner/Resource.cs b/src/Turnierplan.Core/ResourcePlanner/Resource.cs index a2d32f6d..35d7419e 100644 --- a/src/Turnierplan.Core/ResourcePlanner/Resource.cs +++ b/src/Turnierplan.Core/ResourcePlanner/Resource.cs @@ -16,7 +16,7 @@ internal Resource(long id, ResourceType type, string name, string? notes) _notes = notes; } - public Resource(ResourcePlanner resourcePlanner, ResourceType type, string name, string? notes) + internal Resource(ResourcePlanner resourcePlanner, ResourceType type, string name, string? notes) { Id = 0; ResourcePlanner = resourcePlanner; @@ -34,7 +34,17 @@ public Resource(ResourcePlanner resourcePlanner, ResourceType type, string name, public string Name { get => _name; - set => _name = value.Trim(); + set + { + var trimmed = value.Trim(); + + if (string.IsNullOrEmpty(trimmed)) + { + throw new TurnierplanException($"The resource {nameof(Name)} must be a non-empty string."); + } + + _name = trimmed; + } } public string? Notes diff --git a/src/Turnierplan.Core/ResourcePlanner/ResourceGroup.cs b/src/Turnierplan.Core/ResourcePlanner/ResourceGroup.cs index 4a5faf19..0ebb6d6b 100644 --- a/src/Turnierplan.Core/ResourcePlanner/ResourceGroup.cs +++ b/src/Turnierplan.Core/ResourcePlanner/ResourceGroup.cs @@ -7,132 +7,79 @@ public sealed class ResourceGroup : Entity { internal readonly List _resourceAssignments = []; - private string? _name; - private string? _description; + private string _name; + private string? _notes; - internal ResourceGroup(long id, string? name, string? description, ResourceGroupType type, DateTime? start, DateTime? end) + internal ResourceGroup(long id, string name, string? notes, DateTime? start, DateTime? end) { Id = id; - Type = type; Start = start; End = end; _name = name; - _description = description; + _notes = notes; } - internal ResourceGroup(ResourcePlanner resourcePlanner, string? name, string? description, ResourceGroupType type, DateTime? start, DateTime? end) + internal ResourceGroup(ResourcePlanner resourcePlanner, string name, string? notes, DateTime? start, DateTime? end) { - var isWorkshift = type is ResourceGroupType.Workshift; - var isGeneral = type is ResourceGroupType.General; - - if (!isWorkshift && !isGeneral) + if (string.IsNullOrWhiteSpace(name)) { - throw new TurnierplanException($"Invalid resource type: '{type}'"); + throw new TurnierplanException($"{nameof(Name)} must be a non-empty string."); } - if (isWorkshift && (!start.HasValue || !end.HasValue)) + if (notes is not null && notes.Trim().Length == 0) { - throw new TurnierplanException($"Start and end time must be set if the type is '{ResourceGroupType.Workshift}'"); - } - - if (isGeneral && string.IsNullOrWhiteSpace(name)) - { - throw new TurnierplanException($"Name must be a non-empty string if the type is '{ResourceGroupType.General}'"); + throw new TurnierplanException($"{nameof(Notes)} must be null or a non-empty string."); } Id = 0; ResourcePlanner = resourcePlanner; - Type = type; - Start = isWorkshift ? start : null; - End = isWorkshift ? end : null; + Start = start; + End = end; _name = name; - _description = description; + _notes = notes; } public override long Id { get; protected set; } public ResourcePlanner ResourcePlanner { get; internal set; } = null!; - public string? Name + public string Name { get => _name; set { - var trimmed = value?.Trim(); + var trimmed = value.Trim(); - if (Type is ResourceGroupType.General) + if (string.IsNullOrEmpty(trimmed)) { - if (string.IsNullOrEmpty(trimmed)) - { - throw new TurnierplanException($"If the {nameof(Type)} is {ResourceGroupType.General}, the {nameof(Name)} must be a non-empty string."); - } - } - else if (trimmed is not null && trimmed.Length == 0) - { - throw new TurnierplanException($"{nameof(Name)} must be null or a non-empty string"); + throw new TurnierplanException($"{nameof(Name)} must be a non-empty string."); } _name = trimmed; } } - public string? Description + public string? Notes { - get => _description; + get => _notes; set { var trimmed = value?.Trim(); if (trimmed is not null && trimmed.Length == 0) { - throw new TurnierplanException($"{nameof(Description)} must be null or a non-empty string"); - } - - _description = trimmed; - } - } - - public ResourceGroupType Type { get; } - - public DateTime? Start - { - get; - set - { - if (Type is ResourceGroupType.Workshift && value is null) - { - throw new TurnierplanException($"Start time may not be set to null if type is {ResourceGroupType.Workshift}."); + throw new TurnierplanException($"{nameof(Notes)} must be null or a non-empty string"); } - if (Type is not ResourceGroupType.Workshift && value is not null) - { - throw new TurnierplanException($"Start time may not be set to a non-null value if type is not {ResourceGroupType.Workshift}."); - } - - field = value; + _notes = trimmed; } } - public DateTime? End - { - get; - set - { - if (Type is ResourceGroupType.Workshift && value is null) - { - throw new TurnierplanException($"End time may not be set to null if type is {ResourceGroupType.Workshift}."); - } + public DateTime? Start { get; set; } - if (Type is not ResourceGroupType.Workshift && value is not null) - { - throw new TurnierplanException($"End time may not be set to a non-null value if type is not {ResourceGroupType.Workshift}."); - } - - field = value; - } - } + public DateTime? End { get; set; } public IReadOnlyList ResourceAssignments => _resourceAssignments.AsReadOnly(); @@ -151,6 +98,15 @@ public void AssignResource(Resource resource) _resourceAssignments.Add(new ResourceAssignment(this, resource)); } + public Resource AssignResource(ResourceType type, string name, string? notes) + { + var resource = new Resource(ResourcePlanner, type, name, notes); + + _resourceAssignments.Add(new ResourceAssignment(this, resource)); + + return resource; + } + public void UnassignResource(ResourceAssignment assignment) { _resourceAssignments.Remove(assignment); diff --git a/src/Turnierplan.Core/ResourcePlanner/ResourceGroupType.cs b/src/Turnierplan.Core/ResourcePlanner/ResourceGroupType.cs deleted file mode 100644 index 103a3349..00000000 --- a/src/Turnierplan.Core/ResourcePlanner/ResourceGroupType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Turnierplan.Core.ResourcePlanner; - -public enum ResourceGroupType -{ - // Note: Don't change enum values (DB serialization) - - Workshift = 1, - General = 2 -} diff --git a/src/Turnierplan.Core/ResourcePlanner/ResourcePlanner.cs b/src/Turnierplan.Core/ResourcePlanner/ResourcePlanner.cs index 7001a54e..0687b2f9 100644 --- a/src/Turnierplan.Core/ResourcePlanner/ResourcePlanner.cs +++ b/src/Turnierplan.Core/ResourcePlanner/ResourcePlanner.cs @@ -42,7 +42,7 @@ internal ResourcePlanner(long id, PublicId.PublicId publicId, DateTime createdAt public DateTime CreatedAt { get; } - public string Name { get; } + public string Name { get; set; } public RoleAssignment AddRoleAssignment(Role role, Principal principal) { @@ -57,9 +57,9 @@ public void RemoveRoleAssignment(RoleAssignment roleAssignment) _roleAssignments.Remove(roleAssignment); } - public ResourceGroup AddResourceGroup(string? name, string? description, ResourceGroupType type, DateTime? start, DateTime? end) + public ResourceGroup AddResourceGroup(string name, string? description, DateTime? start, DateTime? end) { - var resourceGroup = new ResourceGroup(this, name, description, type, start, end); + var resourceGroup = new ResourceGroup(this, name, description, start, end); _resourceGroups.Add(resourceGroup); return resourceGroup; diff --git a/src/Turnierplan.Dal/EntityConfigurations/ResourceGroupEntityTypeConfiguration.cs b/src/Turnierplan.Dal/EntityConfigurations/ResourceGroupEntityTypeConfiguration.cs index 08a47662..c539fea4 100644 --- a/src/Turnierplan.Dal/EntityConfigurations/ResourceGroupEntityTypeConfiguration.cs +++ b/src/Turnierplan.Dal/EntityConfigurations/ResourceGroupEntityTypeConfiguration.cs @@ -15,13 +15,11 @@ public void Configure(EntityTypeBuilder builder) builder.Property(x => x.Id) .IsRequired(); - builder.Property(x => x.Name); - - builder.Property(x => x.Description); - - builder.Property(x => x.Type) + builder.Property(x => x.Name) .IsRequired(); + builder.Property(x => x.Notes); + builder.Property(x => x.Start); builder.Property(x => x.End); diff --git a/src/Turnierplan.Dal/Migrations/20260717182006_Add_ResourcePlanner.Designer.cs b/src/Turnierplan.Dal/Migrations/20260729083005_Add_ResourcePlanner.Designer.cs similarity index 99% rename from src/Turnierplan.Dal/Migrations/20260717182006_Add_ResourcePlanner.Designer.cs rename to src/Turnierplan.Dal/Migrations/20260729083005_Add_ResourcePlanner.Designer.cs index bbf5e99f..d6cff0a3 100644 --- a/src/Turnierplan.Dal/Migrations/20260717182006_Add_ResourcePlanner.Designer.cs +++ b/src/Turnierplan.Dal/Migrations/20260729083005_Add_ResourcePlanner.Designer.cs @@ -13,7 +13,7 @@ namespace Turnierplan.Dal.Migrations { [DbContext(typeof(TurnierplanContext))] - [Migration("20260717182006_Add_ResourcePlanner")] + [Migration("20260729083005_Add_ResourcePlanner")] partial class Add_ResourcePlanner { /// @@ -342,13 +342,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Description") - .HasColumnType("text"); - b.Property("End") .HasColumnType("timestamp with time zone"); b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Notes") .HasColumnType("text"); b.Property("ResourcePlannerId") @@ -357,9 +358,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Property("Start") .HasColumnType("timestamp with time zone"); - b.Property("Type") - .HasColumnType("integer"); - b.HasKey("Id"); b.HasIndex("ResourcePlannerId"); diff --git a/src/Turnierplan.Dal/Migrations/20260717182006_Add_ResourcePlanner.cs b/src/Turnierplan.Dal/Migrations/20260729083005_Add_ResourcePlanner.cs similarity index 98% rename from src/Turnierplan.Dal/Migrations/20260717182006_Add_ResourcePlanner.cs rename to src/Turnierplan.Dal/Migrations/20260729083005_Add_ResourcePlanner.cs index 82ad7fc3..0d299505 100644 --- a/src/Turnierplan.Dal/Migrations/20260717182006_Add_ResourcePlanner.cs +++ b/src/Turnierplan.Dal/Migrations/20260729083005_Add_ResourcePlanner.cs @@ -67,9 +67,8 @@ protected override void Up(MigrationBuilder migrationBuilder) Id = table.Column(type: "bigint", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), ResourcePlannerId = table.Column(type: "bigint", nullable: false), - Name = table.Column(type: "text", nullable: true), - Description = table.Column(type: "text", nullable: true), - Type = table.Column(type: "integer", nullable: false), + Name = table.Column(type: "text", nullable: false), + Notes = table.Column(type: "text", nullable: true), Start = table.Column(type: "timestamp with time zone", nullable: true), End = table.Column(type: "timestamp with time zone", nullable: true) }, diff --git a/src/Turnierplan.Dal/Migrations/TurnierplanContextModelSnapshot.cs b/src/Turnierplan.Dal/Migrations/TurnierplanContextModelSnapshot.cs index 1b592ec7..f334aa7d 100644 --- a/src/Turnierplan.Dal/Migrations/TurnierplanContextModelSnapshot.cs +++ b/src/Turnierplan.Dal/Migrations/TurnierplanContextModelSnapshot.cs @@ -339,13 +339,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Description") - .HasColumnType("text"); - b.Property("End") .HasColumnType("timestamp with time zone"); b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Notes") .HasColumnType("text"); b.Property("ResourcePlannerId") @@ -354,9 +355,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Start") .HasColumnType("timestamp with time zone"); - b.Property("Type") - .HasColumnType("integer"); - b.HasKey("Id"); b.HasIndex("ResourcePlannerId");