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
8 changes: 7 additions & 1 deletion api-goldens/dashboards-ng/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ export class SiFlexibleDashboardComponent implements OnInit, OnChanges, OnDestro
readonly dashboard: _angular_core.Signal<SiDashboardComponent>;
readonly dashboardId: _angular_core.InputSignal<string | undefined>;
readonly editable: _angular_core.ModelSignal<boolean>;
// (undocumented)
readonly enableMultiSelect: _angular_core.InputSignalWithTransform<boolean, unknown>;
readonly grid: _angular_core.Signal<SiGridComponent>;
readonly heading: _angular_core.InputSignal<string | undefined>;
readonly hideAddWidgetInstanceButton: _angular_core.InputSignal<boolean>;
Expand Down Expand Up @@ -240,7 +242,10 @@ export class SiGridComponent implements OnInit, OnChanges, OnDestroy {

// @public
export class SiWidgetCatalogComponent extends SiWidgetEditorBase implements OnInit {
readonly closed: _angular_core.OutputEmitterRef<Omit<WidgetConfig, "id"> | undefined>;
constructor();
readonly closed: _angular_core.OutputEmitterRef<Omit<WidgetConfig, "id">[] | undefined>;
// (undocumented)
readonly enableMultiSelect: _angular_core.InputSignalWithTransform<boolean, unknown>;
readonly searchPlaceholder: _angular_core.InputSignal<_siemens_element_translate_ng_translate.TranslatableString>;
widgetCatalog: Widget[];
}
Expand Down Expand Up @@ -319,6 +324,7 @@ export interface WidgetConfig {
minHeight?: number;
minWidth?: number;
payload?: any;
setupPending?: boolean;
version?: string;
widgetId: string;
width?: number;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,61 @@
- textbox "Search widget"
- text: Widget catalog list
- listbox "Widget catalog list":
- option "report status none Hello World A dummy widget for testing." [selected]:
- option "report status none Hello World A dummy widget for testing.":
- checkbox
- status "report status none"
- text: ""
- option "user status none Contact Add a contact card to your dashboard.":
- checkbox
- status "user status none"
- text: ""
- option "trend status none Line Chart A line chart is a type of chart used to show information that changes over time. Line charts are created by plotting a series of several points and connecting them with a straight line. Line charts are used to track changes over short and long periods.":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Bar Chart This is a bar chart widget.":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Circle Chart This is a cart with a circle.":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Gauge Chart A nice gauge charts":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none List Widget Displays a list of items":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Timeline Widget Displays events or steps over a period of time":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Value Widget Displays a single KPI":
- checkbox
- status "trend status none"
- text: ""
- option "status none Note (web-component)":
- checkbox
- status "status none"
- text: ""
- option "status none Contact (web-component)":
- checkbox
- status "status none"
- text: ""
- option "status none Chart (web-component)":
- checkbox
- status "status none"
- text: ""
- option "status none Download (module-federation)":
- checkbox
- status "status none"
- text: ""
- option "status none Upload (module-federation)":
- checkbox
- status "status none"
- text: ""
- button "Cancel"
- button "Next"
- button "Add" [disabled]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,61 @@
- textbox "Search widget"
- text: Widget catalog list
- listbox "Widget catalog list":
- option "report status none Hello World A dummy widget for testing." [selected]:
- option "report status none Hello World A dummy widget for testing.":
- checkbox
- status "report status none"
- text: ""
- option "user status none Contact Add a contact card to your dashboard.":
- checkbox
- status "user status none"
- text: ""
- option "trend status none Line Chart A line chart is a type of chart used to show information that changes over time. Line charts are created by plotting a series of several points and connecting them with a straight line. Line charts are used to track changes over short and long periods.":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Bar Chart This is a bar chart widget.":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Circle Chart This is a cart with a circle.":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Gauge Chart A nice gauge charts":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none List Widget Displays a list of items":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Timeline Widget Displays events or steps over a period of time":
- checkbox
- status "trend status none"
- text: ""
- option "trend status none Value Widget Displays a single KPI":
- checkbox
- status "trend status none"
- text: ""
- option "status none Note (web-component)":
- checkbox
- status "status none"
- text: ""
- option "status none Contact (web-component)":
- checkbox
- status "status none"
- text: ""
- option "status none Chart (web-component)":
- checkbox
- status "status none"
- text: ""
- option "status none Download (native-federation)":
- checkbox
- status "status none"
- text: ""
- option "status none Upload (module-federation on native-federation shell)":
- checkbox
- status "status none"
- text: ""
- button "Cancel"
- button "Next"
- button "Add" [disabled]
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<button
type="button"
class="list-group-item list-group-item-action d-flex align-items-center"
[class.active]="selected() === myDescriptor"
(click)="selected.set(myDescriptor)"
[class.active]="selectedWidgets()[0] === myDescriptor"
(click)="selectedWidgets.set([myDescriptor])"
>
<si-circle-status class="my-n4 me-5" [icon]="myDescriptor.iconClass" />
<div class="d-flex flex-column align-items-start">
Expand All @@ -28,7 +28,11 @@
<button type="button" class="btn btn-secondary" (click)="onCancel()">{{
'DASHBOARD.WIDGET_LIBRARY.CANCEL' | translate
}}</button>
<button type="button" class="btn btn-primary" [disabled]="!selected()" (click)="onAddWidget()">{{
'DASHBOARD.WIDGET_LIBRARY.ADD' | translate
}}</button>
<button
type="button"
class="btn btn-primary"
[disabled]="!selectedWidgets()[0]"
(click)="onAddWidget()"
>{{ 'DASHBOARD.WIDGET_LIBRARY.ADD' | translate }}</button
>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { HELLO_DESCRIPTOR } from '../../widgets/hello-widget/widget-descriptors'
styleUrl: './custom-widget-catalog.component.scss'
})
export class CustomWidgetCatalogComponent extends SiWidgetCatalogComponent {
override readonly closed = output<Omit<WidgetConfig, 'id'> | undefined>();
override readonly closed = output<Omit<WidgetConfig, 'id'>[] | undefined>();

override widgetCatalog: Widget[] = [];

Expand All @@ -27,7 +27,7 @@ export class CustomWidgetCatalogComponent extends SiWidgetCatalogComponent {
}

override onAddWidget(): void {
const selected = this.selected();
const selected = this.selectedWidgets()[0];
if (selected) {
const widgetConfig: Omit<WidgetConfig, 'id'> = {
heading: selected.name,
Expand All @@ -37,7 +37,7 @@ export class CustomWidgetCatalogComponent extends SiWidgetCatalogComponent {
...selected.defaults,
payload: { ...selected.payload }
};
this.closed.emit(widgetConfig);
this.closed.emit([widgetConfig]);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
heading="Sample Dashboard"
[widgetCatalog]="widgetCatalog"
[showEditButtonLabel]="true"
[enableMultiSelect]="true"
(isModified)="appStateService.editable$.next($event)"
>
<app-dashboard-filters menubar filters-slot />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ let widgetConfig: Omit<WidgetConfig, 'id'>;
template: ''
})
export class SiWidgetCatalogMockComponent extends SiWidgetCatalogComponent implements OnInit {
static staticClosed: OutputEmitterRef<Omit<WidgetConfig, 'id'> | undefined> | undefined =
static staticClosed: OutputEmitterRef<Omit<WidgetConfig, 'id'>[] | undefined> | undefined =
undefined;

override readonly closed = output<Omit<WidgetConfig, 'id'> | undefined>();
override readonly closed = output<Omit<WidgetConfig, 'id'>[] | undefined>();

override ngOnInit(): void {
SiWidgetCatalogMockComponent.staticClosed ??= this.closed;
Expand Down Expand Up @@ -164,7 +164,7 @@ describe('SiFlexibleDashboardComponent', () => {
fixture.detectChanges();
component.showWidgetCatalog();
fixture.detectChanges();
SiWidgetCatalogMockComponent.staticClosed?.emit({ widgetId: 'widgetId' });
SiWidgetCatalogMockComponent.staticClosed?.emit([{ widgetId: 'widgetId' }]);
vi.advanceTimersByTime(200);
await fixture.whenStable();
expect(widgetConfig).toBeDefined();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
import { AsyncPipe } from '@angular/common';
import {
booleanAttribute,
Component,
computed,
inject,
Expand Down Expand Up @@ -155,6 +156,11 @@ export class SiFlexibleDashboardComponent implements OnInit, OnChanges, OnDestro
*/
readonly secondaryEditActions = input<DashboardToolbarItem[]>([]);

/** @defaultValue false */
readonly enableMultiSelect = input(false, {
transform: booleanAttribute
});

/**
* The grid component is the actual container for the widgets.
*/
Expand Down Expand Up @@ -275,13 +281,12 @@ export class SiFlexibleDashboardComponent implements OnInit, OnChanges, OnDestro
const componentType = this.widgetCatalogComponent() ?? SiWidgetCatalogComponent;
const catalogRef = this.catalogHost().createComponent<SiWidgetCatalogComponent>(componentType, {
bindings: [
inputBinding('enableMultiSelect', this.enableMultiSelect),
inputBinding('searchPlaceholder', this.searchPlaceholder),
outputBinding<Omit<WidgetConfig, 'id'> | undefined>('closed', widgetConfig => {
outputBinding<Omit<WidgetConfig, 'id'>[] | undefined>('closed', widgetConfigs => {
this.viewState.set('dashboard');
this.catalogHost().clear();
if (widgetConfig) {
this.grid().addWidgetInstance(widgetConfig);
}
widgetConfigs?.forEach(config => this.grid().addWidgetInstance(config));
})
]
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ export class SiGridstackWrapperComponent implements OnInit, OnChanges {
*
* @defaultValue new Map()
*/
readonly widgetCatalogMap = input<Map<string, { componentFactory: WidgetComponentFactory }>>(
new Map()
);
readonly widgetCatalogMap = input<
Map<string, { componentFactory: WidgetComponentFactory; iconClass?: string }>
>(new Map());

/**
* Emits dashboard grid events.
Expand Down Expand Up @@ -215,11 +215,16 @@ export class SiGridstackWrapperComponent implements OnInit, OnChanges {
() => this.widgetCatalogMap().get(item.widgetId)?.componentFactory
);

const iconClass = computed(
() => this.widgetCatalogMap().get(item.widgetId)?.iconClass ?? 'element-apps'
);

const componentRef = this.gridstackContainer()!.createComponent(SiWidgetHostComponent, {
bindings: [
inputBinding('widgetConfig', configSignal),
inputBinding('editable', this.editable),
inputBinding('componentFactory', componentFactory),
inputBinding('iconClass', iconClass),
outputBinding<string>('remove', widgetId => {
this.widgetInstanceRemove.emit(widgetId);
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="si-layout-fixed-height mb-8 mx-0 overflow-auto px-2 pt-2">
@if (view() === 'list') {
<div class="si-layout-fixed-height">
<div class="mx-0">
<div class="mx-0 d-flex">
<si-search-bar
class="w-100"
colorVariant="base-1"
Expand All @@ -20,15 +20,25 @@
class="si-layout-fixed-height list-group overflow-auto mb-0"
aria-labelledby="widget-catalog-list-description"
cdkListbox
[cdkListboxValue]="[]"
(cdkListboxValueChange)="selectWidget($event.value[0])"
[cdkListboxValue]="selectedWidgets()"
[cdkListboxMultiple]="enableMultiSelect()"
(cdkListboxValueChange)="selectWidgets($event.value)"
>
@for (widget of filteredWidgetCatalog; track $index) {
<li
class="list-group-item list-group-item-action d-flex"
class="list-group-item d-flex list-group-item-action"
[cdkOption]="widget"
[class.active]="selected() === widget"
[class.active]="selectedWidgets().includes(widget)"
>
@if (enableMultiSelect()) {
<div class="form-check d-flex align-items-center me-5" inert>
<input
type="checkbox"
class="form-check-input"
[checked]="selectedWidgets().includes(widget)"
/>
</div>
}
<si-circle-status class="my-n4 me-5" [icon]="widget.iconClass" />
<div class="d-flex flex-column align-items-start align-self-center">
<span class="si-h5">{{ widget.name | translate }}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@

.list-group-item {
cursor: pointer;

.form-check {
block-size: 2.5rem;
}
}

.catalog-footer {
Expand Down
Loading
Loading