Meeting Type
What kind of meeting are you organizing for your open source project?
diff --git a/apps/lfx-one/src/app/modules/project/meetings/components/meeting-type-selection/meeting-type-selection.component.ts b/apps/lfx-one/src/app/modules/project/meetings/components/meeting-type-selection/meeting-type-selection.component.ts
index f0d22191..934e868b 100644
--- a/apps/lfx-one/src/app/modules/project/meetings/components/meeting-type-selection/meeting-type-selection.component.ts
+++ b/apps/lfx-one/src/app/modules/project/meetings/components/meeting-type-selection/meeting-type-selection.component.ts
@@ -2,12 +2,18 @@
// SPDX-License-Identifier: MIT
import { CommonModule } from '@angular/common';
-import { Component, input } from '@angular/core';
+import { HttpParams } from '@angular/common/http';
+import { Component, computed, inject, input } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
import { MessageComponent } from '@components/message/message.component';
+import { SelectComponent } from '@components/select/select.component';
import { ToggleComponent } from '@components/toggle/toggle.component';
import { MeetingType } from '@lfx-one/shared/enums';
+import { Project } from '@lfx-one/shared/interfaces';
+import { ProjectService } from '@services/project.service';
import { TooltipModule } from 'primeng/tooltip';
+import { map, of } from 'rxjs';
interface MeetingTypeInfo {
icon: string;
@@ -19,13 +25,26 @@ interface MeetingTypeInfo {
@Component({
selector: 'lfx-meeting-type-selection',
standalone: true,
- imports: [CommonModule, ReactiveFormsModule, MessageComponent, ToggleComponent, TooltipModule],
+ imports: [CommonModule, ReactiveFormsModule, MessageComponent, SelectComponent, ToggleComponent, TooltipModule],
templateUrl: './meeting-type-selection.component.html',
})
export class MeetingTypeSelectionComponent {
+ private readonly projectService = inject(ProjectService);
+
// Form group input from parent
public readonly form = input.required
();
+ // Child projects signal
+ public childProjects = this.initializeChildProjects();
+
+ // Map projects to select options
+ public projectOptions = computed(() => {
+ return this.childProjects().map((project: Project) => ({
+ label: project.name,
+ value: project.uid,
+ }));
+ });
+
// Meeting type options using shared enum (excluding NONE for selection)
public readonly meetingTypeOptions = [
{ label: 'Board', value: MeetingType.BOARD },
@@ -92,4 +111,24 @@ export class MeetingTypeSelectionComponent {
this.form().get('meeting_type')?.setValue(meetingType);
this.form().get('meeting_type')?.markAsTouched();
}
+
+ // Get child projects for the current project
+ private initializeChildProjects() {
+ const currentProject = this.projectService.project();
+
+ if (!currentProject) {
+ return toSignal(of([]), { initialValue: [] });
+ }
+
+ const params = new HttpParams().set('tags', `parent_uid:${currentProject.uid}`);
+ return toSignal(
+ this.projectService.getProjects(params).pipe(
+ map((projects: Project[]) => {
+ // Filter out the current project from the list
+ return projects.filter((project) => project.uid !== currentProject.uid);
+ })
+ ),
+ { initialValue: [] }
+ );
+ }
}
diff --git a/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.html b/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.html
new file mode 100644
index 00000000..c4a259b8
--- /dev/null
+++ b/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.html
@@ -0,0 +1,73 @@
+
+
+
+@if (projects().length > 1) {
+
+
+
+
+
+ @if (displayLogo()) {
+
![]()
+ }
+
+
+
+
+
+
+ {{ displayName() }}
+
+
+
+
+
+
+
+
+
+
+ @for (project of projects(); track project.uid) {
+
+
+
+
+ @if (project.logo_url) {
+
![]()
+ }
+
+
+
+
{{ project.name }}
+
+ } @empty {
+
No projects available
+ }
+
+
+} @else {
+
+
+
+
+
+ @if (displayLogo()) {
+
![]()
+ }
+
+
+
+
+
+
+ {{ displayName() }}
+
+
+
+}
diff --git a/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.scss b/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.scss
new file mode 100644
index 00000000..f764a9f2
--- /dev/null
+++ b/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.scss
@@ -0,0 +1,25 @@
+// Copyright The Linux Foundation and each contributor to LFX.
+// SPDX-License-Identifier: MIT
+
+:host {
+ display: block;
+ width: 100%;
+}
+
+::ng-deep {
+ .project-selector-panel {
+ @apply mt-2 rounded-none border-l-0 border-r-0 border-t;
+
+ &::before {
+ @apply hidden;
+ }
+
+ &::after {
+ @apply hidden;
+ }
+
+ .p-popover-content {
+ @apply rounded-none;
+ }
+ }
+}
diff --git a/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.ts b/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.ts
new file mode 100644
index 00000000..83c7b040
--- /dev/null
+++ b/apps/lfx-one/src/app/shared/components/project-selector/project-selector.component.ts
@@ -0,0 +1,46 @@
+// Copyright The Linux Foundation and each contributor to LFX.
+// SPDX-License-Identifier: MIT
+
+import { CommonModule } from '@angular/common';
+import { Component, computed, input, output } from '@angular/core';
+import { ButtonComponent } from '@components/button/button.component';
+import { Project } from '@lfx-one/shared/interfaces';
+import { Popover } from 'primeng/popover';
+import { PopoverModule } from 'primeng/popover';
+
+@Component({
+ selector: 'lfx-project-selector',
+ standalone: true,
+ imports: [CommonModule, PopoverModule, ButtonComponent],
+ templateUrl: './project-selector.component.html',
+ styleUrl: './project-selector.component.scss',
+})
+export class ProjectSelectorComponent {
+ // Input properties
+ public readonly projects = input.required();
+ public readonly selectedProject = input(null);
+
+ // Output events
+ public readonly projectChange = output();
+
+ // Computed properties
+ protected readonly displayName = computed(() => {
+ const project = this.selectedProject();
+ return project?.name || 'Select Project';
+ });
+
+ protected readonly displayLogo = computed(() => {
+ const project = this.selectedProject();
+ return project?.logo_url || '';
+ });
+
+ // Event handlers
+ protected selectProject(project: Project, popover: Popover): void {
+ this.projectChange.emit(project);
+ popover.hide();
+ }
+
+ protected togglePanel(event: Event, popover: Popover): void {
+ popover.toggle(event);
+ }
+}
diff --git a/apps/lfx-one/src/app/shared/components/sidebar/sidebar.component.html b/apps/lfx-one/src/app/shared/components/sidebar/sidebar.component.html
index 4ff8d1f9..4f65b8ce 100644
--- a/apps/lfx-one/src/app/shared/components/sidebar/sidebar.component.html
+++ b/apps/lfx-one/src/app/shared/components/sidebar/sidebar.component.html
@@ -10,6 +10,13 @@
rgba(0, 0, 0, 0.1) 0px 1px 2px -1px;
"
data-testid="sidebar">
+
+ @if (showProjectSelector()) {
+
+
+
+ }
+