diff --git a/angular-client/src/components/select-dropdown/select-dropdown.component.css b/angular-client/src/components/select-dropdown/select-dropdown.component.css index c3452953..8ec8f3b2 100644 --- a/angular-client/src/components/select-dropdown/select-dropdown.component.css +++ b/angular-client/src/components/select-dropdown/select-dropdown.component.css @@ -52,3 +52,13 @@ ::ng-deep .p-select-option { font-size: 0.8rem; } + +::ng-deep .p-select-empty-message { + font-size: 0.8rem; +} + +::ng-deep .p-select-option-label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.css b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.css index 5c9f47ea..bdb71cd2 100644 --- a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.css +++ b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.css @@ -3,13 +3,63 @@ margin-left: 0px; max-height: 80vh; margin-top: 10px; + display: flex; + flex-direction: column; + gap: 8px; +} + +.presets-row { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 6px; +} + +.preset-select { + flex: 0 1 auto; + min-width: 0; + max-width: 100%; +} + +.presets-row argos-button { + flex-shrink: 0; +} + +.presets-row argos-button ::ng-deep .btn { + white-space: nowrap; +} + +.preset-select ::ng-deep .p-select { + height: 28px !important; + min-height: 28px; + width: 100%; + border-radius: 8px; + display: inline-flex; + align-items: center; +} + +.preset-select ::ng-deep .p-select-label, +.preset-select ::ng-deep .p-select-label.p-placeholder { + width: 100% !important; + padding: 0 0.5rem !important; + font-size: 12px; + line-height: 28px; + height: 28px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.preset-select ::ng-deep .p-select-dropdown { + width: 1.75rem; } .header-row { display: flex; align-items: center; - justify-content: space-between; - gap: 12px; + justify-content: flex-start; + gap: 16px; + flex-wrap: wrap; } .toggle-group { diff --git a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.html b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.html index 39f4bb55..0a3d0d05 100644 --- a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.html +++ b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.html @@ -1,8 +1,23 @@
+
+ + +
diff --git a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.ts b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.ts index 9249097e..f51c9ac9 100644 --- a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.ts +++ b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-desktop/graph-sidebar-desktop.component.ts @@ -1,9 +1,17 @@ -import { Component, Injector, OnInit, computed, inject, input, signal } from '@angular/core'; +import { Component, Injector, OnDestroy, OnInit, computed, inject, input, signal } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { FormsModule } from '@angular/forms'; import { TreeNode, PrimeTemplate } from 'primeng/api'; +import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog'; import { TreeNodeSelectEvent, TreeNodeUnSelectEvent, Tree } from 'primeng/tree'; import { ToggleSwitch } from 'primeng/toggleswitch'; +import { take } from 'rxjs'; +import { + DropdownOption, + SelectDropdownComponent, + SelectorConfig +} from 'src/components/select-dropdown/select-dropdown.component'; +import { GraphPresetService, Preset } from 'src/services/graph-preset.service'; import Storage from 'src/services/storage.service'; import { dataTypesToNodes } from 'src/utils/dataTypes.utils'; import { @@ -17,17 +25,21 @@ import { DataType } from 'src/utils/types.utils'; import { TopicSelectionService } from 'src/services/topic-selection.service'; import { ButtonComponent } from '../../../../components/argos-button/argos-button.component'; import TypographyComponent from 'src/components/typography/typography.component'; +import { PresetDialogComponent } from '../../preset-dialog/preset-dialog.component'; @Component({ selector: 'graph-sidebar-desktop', templateUrl: './graph-sidebar-desktop.component.html', styleUrls: ['./graph-sidebar-desktop.component.css'], - imports: [ButtonComponent, Tree, PrimeTemplate, TypographyComponent, ToggleSwitch, FormsModule] + imports: [ButtonComponent, Tree, PrimeTemplate, TypographyComponent, ToggleSwitch, FormsModule, SelectDropdownComponent] }) -export default class GraphSidebarDesktopComponent implements OnInit { +export default class GraphSidebarDesktopComponent implements OnInit, OnDestroy { private topicSelectionService = inject(TopicSelectionService); + private presetService = inject(GraphPresetService); + private dialogService = inject(DialogService); private storage = inject(Storage); private injector = inject(Injector); + private presetDialogRef?: DynamicDialogRef; dataTypes = input([]); treeNodes: TreeNode[] = []; @@ -43,6 +55,18 @@ export default class GraphSidebarDesktopComponent implements OnInit { return this.flattenMode() ? this.flatNodes : this.treeNodes; }); + private presets = toSignal(this.presetService.getPresets(), { initialValue: [] as Preset[] }); + presetSelectorConfig = computed(() => ({ + placeholder: 'Apply Preset…', + options: this.presets().map( + (p): DropdownOption => ({ + name: p.name, + function: () => this.applyPreset(p) + }) + ) + })); + activePresetName = toSignal(this.presetService.getActivePresetName(), { initialValue: undefined }); + ngOnInit(): void { const nodes = dataTypesToNodes(this.dataTypes()); this.treeNodes = mapNodesToTreeNodes(nodes, this.storage, this.injector); @@ -68,6 +92,30 @@ export default class GraphSidebarDesktopComponent implements OnInit { this.selectedNodes = undefined; }; + openPresetsDialog = () => { + this.presetDialogRef = this.dialogService.open(PresetDialogComponent, { + header: 'Topic Presets', + width: '640px', + draggable: true, + closable: true, + closeAriaLabel: 'Close', + data: { + dataTypes: this.dataTypes() + } + }); + this.presetDialogRef.onClose.pipe(take(1)).subscribe((matched: DataType[] | null) => { + if (matched) { + this.applyMatched(matched); + } + }); + }; + + ngOnDestroy(): void { + if (this.presetDialogRef) { + this.presetDialogRef.close(); + } + } + nodeSelect(event: TreeNodeSelectEvent) { const dt = event.node.data?.dataType; if (dt) { @@ -89,4 +137,15 @@ export default class GraphSidebarDesktopComponent implements OnInit { this.topicSelectionService.removeDataType(dt); } } + + private applyPreset(preset: Preset) { + const matched = this.presetService.resolvePresetTopics(preset, this.dataTypes()); + this.applyMatched(matched); + } + + private applyMatched(matched: DataType[]) { + if (matched.length === 0) return; // unknown topics warn toast + this.topicSelectionService.setSelectedDataTypes(matched); + this.selectedNodes = findSelectedTreeNodes(this.activeNodes(), this.topicSelectionService); + } } diff --git a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-mobile/graph-sidebar-mobile.component.css b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-mobile/graph-sidebar-mobile.component.css index 3a2b26b1..64e186e5 100644 --- a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-mobile/graph-sidebar-mobile.component.css +++ b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-mobile/graph-sidebar-mobile.component.css @@ -27,6 +27,52 @@ height: 100%; } +.presets-row { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 6px; +} + +.preset-select { + flex: 0 1 auto; + min-width: 0; + max-width: 100%; +} + +.presets-row argos-button { + flex-shrink: 0; +} + +.presets-row argos-button ::ng-deep .btn { + white-space: nowrap; +} + +.preset-select ::ng-deep .p-select { + height: 28px !important; + min-height: 28px; + width: 100%; + border-radius: 8px; + display: inline-flex; + align-items: center; +} + +.preset-select ::ng-deep .p-select-label, +.preset-select ::ng-deep .p-select-label.p-placeholder { + width: 100% !important; + padding: 0 0.5rem !important; + font-size: 12px; + line-height: 28px; + height: 28px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.preset-select ::ng-deep .p-select-dropdown { + width: 1.75rem; +} + .toggle-group { display: inline-flex; align-items: center; diff --git a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-mobile/graph-sidebar-mobile.component.html b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-mobile/graph-sidebar-mobile.component.html index fe998c27..54221ab6 100644 --- a/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-mobile/graph-sidebar-mobile.component.html +++ b/angular-client/src/pages/graph-page/graph-sidebar/graph-sidebar-mobile/graph-sidebar-mobile.component.html @@ -6,9 +6,24 @@