Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,75 @@
</div>

<div class="wrapper">

<div class="flex flex-wrap flex-col gap-4 md:flex-row">
<div class="flex flex-wrap flex-1 items-center gap-4 p-6 bg-dark-300 rounded-lg">
<div class="flex-1 min-w-[240px]">
<!--Editor de nombre y description (modificar a que la description sea traducible como el nombre de proyecto)-->
<div *ngIf="!isEditing">
<p><strong>{{'project.edit.editing' | translate}}: {{ project?.name }}</strong></p>
<p>{{ project?.description !== undefined && project?.description !== null ? project.description : 'No description' }}</p>

</div>

<div *ngIf="isEditing">
<label for="">{{'project.edit.editing' | translate}}</label>
<hr><br>
<input [(ngModel)]="editName" class="w-full mb-2 p-1 bg-dark-400">
<textarea [(ngModel)]="editDescription" class="w-full p-1 bg-dark-400" rows="2"></textarea>
</div>
<!--
<p class="flex">{{ 'project.edit.editing' | translate }}: {{ project?.name }}</p>
<p class="flex">{{'Description' | translate }}: {{project?.description}}</p>
Mapeo automático de la descripción:
<p>{{ project?.description ?? project?.CuemsScript?.description ?? ('No description' | translate) }}</p>
-->
</div>

<div class="flex gap-4">
<button
*ngIf="hasUnsavedChanges"
class="btn btn-normal btn-primary gap-2"
(click)="saveAllChanges()">
<app-icon icon="upload" class="w-4 h-4"></app-icon>
{{ 'project.edit.save.changes' | translate }}
</button>

<button *ngIf="!isEditing" class="btn btn-normal btn-primary" (click)="startEdit()">
{{ 'project.edit' | translate }}
</button>

<button *ngIf="isEditing" class="btn btn-normal btn-primary" (click)="saveEdit()">
{{'save' | translate}}
</button>
<button *ngIf="isEditing" class="btn btn-normal btn-muted ml-2" (click)="cancelEdit()">
{{'cancel' | translate}}
</button>

<a [routerLink]="['/projects', project?.uuid]" class="btn btn-normal btn-muted">{{ 'project.show' | translate }}</a>
</div>
</div>

<!--
<div>
<button class="btn btn-large btn-muted" disabled>GO</button>
</div>
-->
</div>

<!-- Tab routes -->
<div class="mt-6 border-b border-dark-300">
<div class="flex justify-between">
<nav class="flex space-x-4">
<a routerLink="sequence" routerLinkActive="bg-dark-300 text-white" class="px-4 py-2 text-sm font-medium rounded-t-lg">
{{ 'project.sequence' | translate }}
</a>
<a routerLink="audio-mixer" routerLinkActive="bg-dark-300 text-white" class="pointer-events-none text-muted px-4 py-2 text-sm font-medium rounded-t-lg">
{{ 'project.audio-mixer' | translate }}
</a>
<a routerLink="video-mixer" routerLinkActive="bg-dark-300 text-white" class="pointer-events-none text-muted px-4 py-2 text-sm font-medium rounded-t-lg">
{{ 'project.video-mixer' | translate }}
</a>
<a routerLink="dmx-mixer" routerLinkActive="bg-dark-300 text-white" class="px-4 py-2 text-sm font-medium rounded-t-lg">
</a>
<a routerLink="audio-mixer" routerLinkActive="bg-dark-300 text-white" class="pointer-events-none text-muted px-4 py-2 text-sm font-medium rounded-t-lg">
{{ 'project.audio-mixer' | translate }}
</a>
<a routerLink="video-mixer" routerLinkActive="bg-dark-300 text-white" class="pointer-events-none text-muted px-4 py-2 text-sm font-medium rounded-t-lg">
{{ 'project.video-mixer' | translate }}
</a>
<a routerLink="dmx-mixer" routerLinkActive="bg-dark-300 text-white" class="px-4 py-2 text-sm font-medium rounded-t-lg">
{{ 'project.dmx-mixer' | translate }}
</a>
</nav>
Expand All @@ -51,16 +105,16 @@
<app-icon icon="activity"></app-icon>
<span>{{ 'project.button.activity' | translate }} / {{ 'project.button.warnings' | translate }}</span>
</button>

<button class="btn btn-small btn-muted space-x-2">
<app-icon icon="star"></app-icon>
<span>{{ 'project.button.effects' | translate }}</span>
</button>
</div>
</div>
</div>

<div class="mt-4">
<router-outlet></router-outlet>
</div>
</div>
</div>
98 changes: 81 additions & 17 deletions src/app/components/projects/project-edit/project-edit.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,45 @@ import { ProjectEditStateService } from '../../../services/projects/project-edit
import { IconComponent } from '../../ui/icon/icon.component';
import { DrawerService } from '../../../services/ui/drawer.service';
import { v4 as uuidv4 } from 'uuid';
import { FormsModule } from '@angular/forms';
import { ProjectWorkspaceService } from '../../../services/project-workspace.service';

@Component({
selector: 'app-project-edit',
standalone: true,
imports: [CommonModule, RouterModule, AppPageHeaderComponent, TranslateModule, IconComponent],
imports: [CommonModule, RouterModule, AppPageHeaderComponent, TranslateModule, IconComponent, FormsModule],
templateUrl: './project-edit.component.html'
})
export class ProjectEditComponent implements OnInit, OnDestroy {
private route = inject(ActivatedRoute);
private projectsService = inject(ProjectsService);
private editStateService = inject(ProjectEditStateService);
private drawerService = inject(DrawerService);

private workspace = inject(ProjectWorkspaceService);

public project: any;
public projectUuid: string | null = null;
public hasUnsavedChanges: boolean = false;
private changesSubscription?: Subscription;
private projectLoadedSubscription?: Subscription;
private projectSavedSubscription?: Subscription;

//edición de descripción y nombre de proyectos=
public isEditing: boolean = false;
public editName: string = '';
public editDescription: string = '';


ngOnInit(): void {
this.route.params.subscribe(params => {
this.projectUuid = params['uuid'];

if (this.projectUuid) {
if (this.projectsService.projects().length === 0) {
this.projectsService.getProjectList();
}

this.projectsService.loadProject(this.projectUuid);
this.workspace.openInEdit(this.projectUuid, this.projectUuid); // register immediately, name updated later
}
Expand All @@ -48,9 +56,18 @@ export class ProjectEditComponent implements OnInit, OnDestroy {
this.projectLoadedSubscription = this.projectsService.projectLoaded.subscribe(projectData => {
if (projectData) {
const basicProjectData = this.projectsService.projects().find(p => p.uuid === this.projectUuid);

//Mapear descripción desde CuemsScript si no existe
if (!projectData.description && projectData.CuemsScript?.description) {
projectData.description = projectData.CuemsScript.description;
}

if (basicProjectData) {
if (!projectData.uuid) projectData.uuid = basicProjectData.uuid;
if (!projectData.name) projectData.name = basicProjectData.name;

if (!projectData.description && basicProjectData.description) projectData.description = basicProjectData.description; //revisar ProjectList

if (!projectData.unix_name) projectData.unix_name = basicProjectData.unix_name;
if (!projectData.created) projectData.created = basicProjectData.created;
if (!projectData.modified) projectData.modified = basicProjectData.modified;
Expand All @@ -59,7 +76,7 @@ export class ProjectEditComponent implements OnInit, OnDestroy {
projectData.uuid = this.projectUuid;
}
}

this.project = projectData;

// Workaround: server returns stale CuemsScript.id and CuemsScript.name on duplicated projects.
Expand Down Expand Up @@ -90,8 +107,6 @@ export class ProjectEditComponent implements OnInit, OnDestroy {
savedProjectUuid => {
if (this.projectUuid && savedProjectUuid === this.projectUuid) {
this.editStateService.markProjectAsSaved(this.projectUuid);

this.projectsService.loadProject(this.projectUuid);
}
}
);
Expand All @@ -101,7 +116,7 @@ export class ProjectEditComponent implements OnInit, OnDestroy {
this.changesSubscription?.unsubscribe();
this.projectLoadedSubscription?.unsubscribe();
this.projectSavedSubscription?.unsubscribe();

if (this.projectUuid) {
this.editStateService.clearTemporaryCues(this.projectUuid);
}
Expand All @@ -125,13 +140,33 @@ export class ProjectEditComponent implements OnInit, OnDestroy {

try {
const updatedProject = JSON.parse(JSON.stringify(this.project));

const modifiedData = this.editStateService.getProjectModifiedData(this.projectUuid);

if (!modifiedData || Object.keys(modifiedData).length === 0) {
return;
}


//guardar cambios de nombre y descripción
if (modifiedData.metadata) {

if (!updatedProject.CuemsScript) {
updatedProject.CuemsScript = {};
}

if (modifiedData.metadata.name !== undefined && modifiedData.metadata.name.trim() !== '') {
updatedProject.name = modifiedData.metadata.name;

updatedProject.CuemsScript.name = modifiedData.metadata.name;
}

if (modifiedData.metadata.description !== undefined) {
updatedProject.description = modifiedData.metadata.description;

updatedProject.CuemsScript.description = modifiedData.metadata.description;
}
}

if (modifiedData.sequence) {
if (!updatedProject.CuemsScript) {
updatedProject.CuemsScript = {};
Expand All @@ -146,7 +181,7 @@ export class ProjectEditComponent implements OnInit, OnDestroy {
updatedProject.CuemsScript.CueList.id = this.generateUUID();
updatedProject.CuemsScript.CueList.contents = [];
} else {
// Fallback
// Fallback
updatedProject.CuemsScript.CueList = {
autoload: false,
description: null,
Expand All @@ -165,7 +200,7 @@ export class ProjectEditComponent implements OnInit, OnDestroy {
};
}
}

if (modifiedData.sequence.contents === null) {
updatedProject.CuemsScript.CueList.contents = null;
} else if (Array.isArray(modifiedData.sequence.contents) && modifiedData.sequence.contents.length === 0) {
Expand All @@ -174,15 +209,16 @@ export class ProjectEditComponent implements OnInit, OnDestroy {
updatedProject.CuemsScript.CueList.contents = modifiedData.sequence.contents;
}
}

if (!updatedProject.uuid && this.projectUuid) {
updatedProject.uuid = this.projectUuid;
}

this.projectsService.updateProject(updatedProject);
} catch (error) {
console.error('Error saving complete project:', error);
}

}

toggleActivityDrawer(): void {
Expand All @@ -193,9 +229,37 @@ export class ProjectEditComponent implements OnInit, OnDestroy {
return uuidv4();
}

//métodos de edición de nombre y descripción
startEdit(): void {
this.isEditing = true;
this.editName = this.project?.name || '';
this.editDescription = this.project?.description || '';
}

cancelEdit(): void {
this.isEditing = false;
}

saveEdit(): void {
if (!this.project || !this.projectUuid) return;
if (!this.editName.trim()) return;

// Actualiza UI inmediatamente
this.project.name = this.editName;
this.project.description = this.editDescription;

// Registra el cambio en el estado global
this.editStateService.setProjectMetadata(this.projectUuid, {
name: this.editName,
description: this.editDescription
});

this.isEditing = false;
}

closeWorkspaceProject(): void {
if (this.projectUuid) {
this.workspace.requestClose(this.projectUuid);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<input class="checkbox" type="checkbox" (click)="$event.stopPropagation(); selectAllProjects()" [checked]="selectedProjects.length === getSelectableProjects().length" [disabled]="isBulkDeleting">
</th>
<th scope="col" class="w-64 py-3.5 pr-3 pl-4 text-left text-sm font-semibold sm:pl-0">{{ 'project.list.name' | translate }}</th>
<th scope="col" class="w-40 px-3 py-3.5 text-left text-sm font-semibold">{{ 'project.list.unix_name' | translate }}</th>
<th scope="col" class="w-40 px-3 py-3.5 text-left text-sm font-semibold">{{ 'project.list.description' | translate }}</th>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold">{{ 'project.list.created' | translate }}</th>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold">{{ 'project.list.modified' | translate }}</th>
<th scope="col" class="relative py-3.5 pr-4 pl-3 sm:pr-0">
Expand All @@ -74,7 +74,7 @@
<input class="checkbox" type="checkbox" (click)="selectProject(project.uuid)" [checked]="selectedProjects.includes(project.uuid)" [disabled]="isProjectBeingDeleted(project.uuid) || isBulkDeleting">
</td>
<td class="w-64 py-4 pr-3 pl-4 text-sm font-medium whitespace-nowrap sm:pl-0">{{ project.name }}</td>
<td class="w-40 px-3 py-4 text-sm whitespace-nowrap">{{ project.unix_name }}</td>
<td class="w-40 px-3 py-4 text-sm whitespace-nowrap cursor-default" [attr.title]="project.description">{{ truncateText(project.description || '', 17) }}</td>
<td class="px-3 py-4 text-sm whitespace-nowrap">{{ project.created | date:'medium' }}</td>
<td class="px-3 py-4 text-sm whitespace-nowrap">{{ project.modified | date:'medium' }}</td>
<td class="relative py-4 pr-4 pl-3 text-right text-sm font-medium whitespace-nowrap sm:pr-0">
Expand Down
Loading