Browse Source

UI: Add widget action tooltip reference hint and new action replaceReferenceWithWidgetCopy

pull/11430/head
Vladyslav_Prykhodko 2 years ago
parent
commit
07a45573b7
  1. 67
      ui-ngx/src/app/core/services/dashboard-utils.service.ts
  2. 44
      ui-ngx/src/app/core/services/item-buffer.service.ts
  3. 33
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts
  4. 2
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts
  5. 4
      ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts
  6. 2
      ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html
  7. 12
      ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts
  8. 30
      ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss
  9. 74
      ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts
  10. 2
      ui-ngx/src/app/modules/home/models/dashboard-component.models.ts
  11. 6
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  12. 6
      ui-ngx/src/styles.scss

67
ui-ngx/src/app/core/services/dashboard-utils.service.ts

@ -29,7 +29,7 @@ import {
GridSettings,
WidgetLayout
} from '@shared/models/dashboard.models';
import { deepClone, isDefined, isDefinedAndNotNull, isNotEmptyStr, isString, isUndefined, isEqual } from '@core/utils';
import { deepClone, isDefined, isDefinedAndNotNull, isNotEmptyStr, isString, isUndefined } from '@core/utils';
import {
Datasource,
datasourcesHasOnlyComparisonAggregation,
@ -40,7 +40,7 @@ import {
TargetDeviceType,
Widget,
WidgetConfig,
WidgetConfigMode,
WidgetConfigMode, WidgetSize,
widgetType,
WidgetTypeDescriptor
} from '@app/shared/models/widget.models';
@ -933,4 +933,67 @@ export class DashboardUtilsService {
}
}
replaceReferenceWithWidgetCopy(widget: Widget,
dashboard: Dashboard,
targetState: string,
targetLayout: DashboardLayoutId,
breakpointId: string,
isRemoveWidget: boolean): Widget {
const newWidget = deepClone(widget);
newWidget.id = this.utils.guid();
const originalColumns = this.getOriginalColumns(dashboard, targetState, targetLayout, breakpointId);
const originalSize = this.getOriginalSize(dashboard, targetState, targetLayout, widget, breakpointId);
const layout = this.getDashboardLayoutConfig(dashboard.configuration.states[targetState].layouts[targetLayout], breakpointId);
const widgetLayout = layout.widgets[widget.id];
const targetRow = widgetLayout.row;
const targetColumn = widgetLayout.col;
if (isRemoveWidget) {
this.removeWidgetFromLayout(dashboard, targetState, targetLayout, widget.id, breakpointId);
}
this.addWidgetToLayout(dashboard, targetState, targetLayout, newWidget, originalColumns, originalSize,
targetRow, targetColumn, breakpointId);
return newWidget;
}
getDashboardLayoutConfig(layout: DashboardLayout, breakpointId: string): DashboardLayout {
if (breakpointId !== 'default') {
return layout.breakpoints[breakpointId];
}
return layout;
}
getOriginalColumns(dashboard: Dashboard, sourceState: string, sourceLayout: DashboardLayoutId, breakpointId: string): number {
let originalColumns = 24;
let gridSettings = null;
const state = dashboard.configuration.states[sourceState];
const layoutCount = Object.keys(state.layouts).length;
if (state) {
const layout = this.getDashboardLayoutConfig(state.layouts[sourceLayout], breakpointId);
if (layout) {
gridSettings = layout.gridSettings;
}
}
if (gridSettings && gridSettings.columns) {
originalColumns = gridSettings.columns;
}
originalColumns = originalColumns * layoutCount;
return originalColumns;
}
getOriginalSize(dashboard: Dashboard, sourceState: string, sourceLayout: DashboardLayoutId,
widget: Widget, breakpointId: string): WidgetSize {
const layout = this.getDashboardLayoutConfig(dashboard.configuration.states[sourceState].layouts[sourceLayout], breakpointId);
const widgetLayout = layout.widgets[widget.id];
return {
sizeX: widgetLayout.sizeX,
sizeY: widgetLayout.sizeY
};
}
}

44
ui-ngx/src/app/core/services/item-buffer.service.ts

@ -95,8 +95,8 @@ export class ItemBufferService {
const filtersInfo: FiltersInfo = {
datasourceFilters: {}
};
const originalColumns = this.getOriginalColumns(dashboard, sourceState, sourceLayout, breakpoint);
const originalSize = this.getOriginalSize(dashboard, sourceState, sourceLayout, widget, breakpoint);
const originalColumns = this.dashboardUtils.getOriginalColumns(dashboard, sourceState, sourceLayout, breakpoint);
const originalSize = this.dashboardUtils.getOriginalSize(dashboard, sourceState, sourceLayout, widget, breakpoint);
const datasources: Datasource[] = widget.type === widgetType.alarm ? [widget.config.alarmSource] : widget.config.datasources;
if (widget.config && dashboard.configuration
&& dashboard.configuration.entityAliases) {
@ -396,42 +396,6 @@ export class ItemBufferService {
return ruleChainImport;
}
private getOriginalColumns(dashboard: Dashboard, sourceState: string, sourceLayout: DashboardLayoutId,
breakpoint: string): number {
let originalColumns = 24;
let gridSettings = null;
const state = dashboard.configuration.states[sourceState];
const layoutCount = Object.keys(state.layouts).length;
if (state) {
let layout = state.layouts[sourceLayout];
if (breakpoint !== 'default') {
layout = layout.breakpoints[breakpoint];
}
if (layout) {
gridSettings = layout.gridSettings;
}
}
if (gridSettings && gridSettings.columns) {
originalColumns = gridSettings.columns;
}
originalColumns = originalColumns * layoutCount;
return originalColumns;
}
private getOriginalSize(dashboard: Dashboard, sourceState: string, sourceLayout: DashboardLayoutId, widget: Widget,
breakpoint: string): WidgetSize {
let layout = dashboard.configuration.states[sourceState].layouts[sourceLayout];
if (breakpoint !== 'default') {
layout = layout.breakpoints[breakpoint];
}
const widgetLayout = layout.widgets[widget.id];
return {
sizeX: widgetLayout.sizeX,
sizeY: widgetLayout.sizeY
};
}
private prepareAliasInfo(entityAlias: EntityAlias): EntityAliasInfo {
return {
alias: entityAlias.alias,
@ -449,8 +413,8 @@ export class ItemBufferService {
private prepareWidgetReference(dashboard: Dashboard, sourceState: string,
sourceLayout: DashboardLayoutId, widget: Widget, breakpoint: string): WidgetReference {
const originalColumns = this.getOriginalColumns(dashboard, sourceState, sourceLayout, breakpoint);
const originalSize = this.getOriginalSize(dashboard, sourceState, sourceLayout, widget, breakpoint);
const originalColumns = this.dashboardUtils.getOriginalColumns(dashboard, sourceState, sourceLayout, breakpoint);
const originalSize = this.dashboardUtils.getOriginalSize(dashboard, sourceState, sourceLayout, widget, breakpoint);
return {
dashboardId: dashboard.id.id,
sourceState,

33
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts

@ -483,7 +483,6 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
if (!this.widgetEditMode && !this.readonly && this.dashboardUtils.isEmptyDashboard(this.dashboard)) {
this.setEditMode(true, false);
}
this.setEditMode(true, false);
}
private init(data: DashboardPageInitData) {
@ -1419,31 +1418,17 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
}
}
copyEditWidget($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget) {
replaceReferenceWithWidgetCopy($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget) {
$event.stopPropagation();
const widgetItem = deepClone(this.itembuffer.prepareWidgetItem(this.dashboard, this.dashboardCtx.state,
layoutCtx.id, widget, layoutCtx.breakpoint));
const isRemove = layoutCtx.widgets.removeWidgetId(widget.id);
const targetRow = layoutCtx.widgetLayouts[widget.id].row;
const targetColumn = layoutCtx.widgetLayouts[widget.id].col;
const widgetCopy = this.dashboardUtils.replaceReferenceWithWidgetCopy(widget, this.dashboard, this.dashboardCtx.state,
layoutCtx.id, layoutCtx.breakpoint, isRemove);
if (layoutCtx.widgets.removeWidgetId(widget.id)) {
this.dashboardUtils.removeWidgetFromLayout(this.dashboard, this.dashboardCtx.state, layoutCtx.id,
widget.id, layoutCtx.breakpoint);
}
widgetItem.widget.id = this.utils.guid();
layoutCtx.widgets.addWidgetId(widgetCopy.id);
this.itembuffer.addWidgetToDashboard(this.dashboard, this.dashboardCtx.state, layoutCtx.id, widgetItem.widget,
widgetItem.aliasesInfo, widgetItem.filtersInfo,
this.entityAliasesUpdated.bind(this), this.filtersUpdated.bind(this),
widgetItem.originalColumns, widgetItem.originalSize, targetRow, targetColumn, layoutCtx.breakpoint
).subscribe(() => {
layoutCtx.widgets.addWidgetId(widgetItem.widget.id);
this.runChangeDetection();
this.editWidget($event,layoutCtx, widgetItem.widget);
});
this.runChangeDetection();
}
copyWidget($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget) {
@ -1591,11 +1576,11 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
widgetContextActions.push(
{
action: (event, currentWidget) => {
this.copyEditWidget(event, layoutCtx, currentWidget);
this.replaceReferenceWithWidgetCopy(event, layoutCtx, currentWidget);
},
enabled: true,
value: 'widget.copy-edit',
icon: 'edit'
value: 'widget.replace-reference-with-widget-copy',
icon: 'mdi:file-replace-outline'
}
);
}

2
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts

@ -57,7 +57,7 @@ export interface IDashboardController {
openDashboardState(stateId: string, openRightLayout: boolean);
addWidget($event: Event, layoutCtx: DashboardPageLayoutContext);
editWidget($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget);
copyEditWidget($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget);
replaceReferenceWithWidgetCopy($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget);
exportWidget($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget, widgetTitle: string);
removeWidget($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget);
widgetMouseDown($event: Event, layoutCtx: DashboardPageLayoutContext, widget: Widget);

4
ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts

@ -269,8 +269,8 @@ export class DashboardLayoutComponent extends PageComponent implements ILayoutCo
this.layoutCtx.dashboardCtrl.editWidget($event, this.layoutCtx, widget);
}
onCopyEditWidget($event: Event, widget: Widget): void {
this.layoutCtx.dashboardCtrl.copyEditWidget($event, this.layoutCtx, widget);
replaceReferenceWithWidgetCopy($event: Event, widget: Widget): void {
this.layoutCtx.dashboardCtrl.replaceReferenceWithWidgetCopy($event, this.layoutCtx, widget);
}
onExportWidget($event: Event, widget: Widget, widgetTitle: string): void {

2
ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html

@ -58,7 +58,7 @@
[disabled]="!item.enabled"
(click)="item.action(widgetContextMenuEvent, widget)">
<span *ngIf="item.shortcut" class="tb-alt-text"> {{ item.shortcut | keyboardShortcut }}</span>
<mat-icon *ngIf="item.icon">{{item.icon}}</mat-icon>
<tb-icon matMenuItemIcon *ngIf="item.icon">{{item.icon}}</tb-icon>
<span translate>{{item.value}}</span>
</button>
</div>

12
ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts

@ -453,15 +453,15 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
case WidgetComponentActionType.EDIT:
this.editWidget($event, widget);
break;
case WidgetComponentActionType.COPY_EDIT:
this.editCopyWidget($event, widget);
break;
case WidgetComponentActionType.EXPORT:
this.exportWidget($event, widget);
break;
case WidgetComponentActionType.REMOVE:
this.removeWidget($event, widget);
break;
case WidgetComponentActionType.REPLACE_REFERENCE_WITH_WIDGET_COPY:
this.replaceReferenceWithWidgetCopy($event, widget);
break;
}
}
@ -486,12 +486,12 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
}
}
private editCopyWidget($event: Event, widget: DashboardWidget) {
private replaceReferenceWithWidgetCopy($event: Event, widget: DashboardWidget) {
if ($event) {
$event.stopPropagation();
}
if (this.isEditActionEnabled && this.callbacks && this.callbacks.onCopyEditWidget) {
this.callbacks.onCopyEditWidget($event, widget.widget);
if (this.isEditActionEnabled && this.callbacks && this.callbacks.replaceReferenceWithWidgetCopy) {
this.callbacks.replaceReferenceWithWidgetCopy($event, widget.widget);
}
}

30
ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss

@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import '../scss/constants';
.tb-widget-container {
position: absolute;
inset: 0;
@ -182,12 +184,30 @@ gridster-item:hover {
line-height: 12px;
font-weight: 500;
color: rgba(0, 0, 0, 0.76);
.tb-widget-actions-panel {
.tb-widget-action-container {
display: flex;
flex-direction: row;
place-content: center flex-start;
align-items: center;
gap: 8px;
flex-direction: column;
gap: 6px;
.tb-widget-actions-panel {
display: flex;
flex-direction: row;
place-content: center space-between;
align-items: center;
gap: 8px;
}
.tb-widget-reference-panel {
display: flex;
flex-direction: row;
place-content: center space-between;
align-items: center;
gap: 8px;
font-weight: normal;
color: $tb-primary-color;
font-size: 11px;
padding: 4px 4px 4px 6px;
border-radius: 2px;
}
}
}
}

74
ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts

@ -49,7 +49,7 @@ export enum WidgetComponentActionType {
EDIT,
EXPORT,
REMOVE,
COPY_EDIT,
REPLACE_REFERENCE_WITH_WIDGET_COPY,
}
export class WidgetComponentAction {
@ -220,10 +220,10 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, O
});
}
onCopyEdit(event: MouseEvent) {
onReplaceReferenceWithWidgetCopy(event: MouseEvent) {
this.widgetComponentAction.emit({
event,
actionType: WidgetComponentActionType.COPY_EDIT
actionType: WidgetComponentActionType.REPLACE_REFERENCE_WITH_WIDGET_COPY
});
}
@ -343,37 +343,43 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, O
}
@Component({
template: `<div class="tb-widget-actions-panel">
<button mat-icon-button class="tb-mat-20"
*ngIf="container.widget.isReference"
[fxShow]="container.isEditActionEnabled"
(click)="container.onCopyEdit($event)"
matTooltip="{{ 'widget.edit-copy' | translate }}"
matTooltipPosition="above">
<tb-icon>mdi:circle-edit-outline</tb-icon>
</button>
<button mat-icon-button class="tb-mat-20"
[fxShow]="container.isEditActionEnabled"
(click)="container.onEdit($event)"
matTooltip="{{ 'widget.edit' | translate }}"
matTooltipPosition="above">
<tb-icon>edit</tb-icon>
</button>
<button mat-icon-button class="tb-mat-20"
[fxShow]="container.isExportActionEnabled"
(click)="container.onExport($event)"
matTooltip="{{ 'widget.export' | translate }}"
matTooltipPosition="above">
<tb-icon>file_download</tb-icon>
</button>
<button mat-icon-button class="tb-mat-20"
[fxShow]="container.isRemoveActionEnabled"
(click)="container.onRemove($event);"
matTooltip="{{ 'widget.remove' | translate }}"
matTooltipPosition="above">
<tb-icon>close</tb-icon>
</button>
</div>`,
template: `
<div class="tb-widget-action-container">
<div class="tb-widget-reference-panel tb-primary-fill" *ngIf="container.widget.isReference">
{{ 'widget.reference' | translate }}
<button mat-icon-button class="tb-mat-16"
color="primary"
[fxShow]="container.isEditActionEnabled"
(click)="container.onReplaceReferenceWithWidgetCopy($event)"
matTooltip="{{ 'widget.replace-reference-with-widget-copy' | translate }}"
matTooltipPosition="above">
<tb-icon matButtonIcon>mdi:file-replace-outline</tb-icon>
</button>
</div>
<div class="tb-widget-actions-panel">
<button mat-icon-button class="tb-mat-20"
[fxShow]="container.isEditActionEnabled"
(click)="container.onEdit($event)"
matTooltip="{{ 'widget.edit' | translate }}"
matTooltipPosition="above">
<tb-icon>edit</tb-icon>
</button>
<button mat-icon-button class="tb-mat-20"
[fxShow]="container.isExportActionEnabled"
(click)="container.onExport($event)"
matTooltip="{{ 'widget.export' | translate }}"
matTooltipPosition="above">
<tb-icon>file_download</tb-icon>
</button>
<button mat-icon-button class="tb-mat-20"
[fxShow]="container.isRemoveActionEnabled"
(click)="container.onRemove($event);"
matTooltip="{{ 'widget.remove' | translate }}"
matTooltipPosition="above">
<tb-icon>close</tb-icon>
</button>
</div>
</div>`,
styles: [],
encapsulation: ViewEncapsulation.None
})

2
ui-ngx/src/app/modules/home/models/dashboard-component.models.ts

@ -65,7 +65,7 @@ export interface WidgetContextMenuItem extends ContextMenuItem {
export interface DashboardCallbacks {
onEditWidget?: ($event: Event, widget: Widget) => void;
onCopyEditWidget?: ($event: Event, widget: Widget) => void;
replaceReferenceWithWidgetCopy?: ($event: Event, widget: Widget) => void;
onExportWidget?: ($event: Event, widget: Widget, widgeTitle: string) => void;
onRemoveWidget?: ($event: Event, widget: Widget) => void;
onWidgetMouseDown?: ($event: Event, widget: Widget) => void;

6
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -5601,10 +5601,9 @@
"remove": "Remove widget",
"delete": "Delete widget",
"edit": "Edit widget",
"edit-copy": "Edit copy widget",
"copy-edit": "Copy and edit",
"remove-widget-title": "Are you sure you want to remove the widget '{{widgetTitle}}'?",
"remove-widget-text": "After the confirmation the widget and all related data will become unrecoverable.",
"replace-reference-with-widget-copy": "Replace reference with widget copy",
"timeseries": "Time series",
"search-data": "Search data",
"no-data-found": "No data found",
@ -5685,7 +5684,8 @@
"search": "Search widget",
"filter": "Widget filter type",
"loading-widgets": "Loading widgets...",
"widget-template-error": "Invalid widget HTML template."
"widget-template-error": "Invalid widget HTML template.",
"reference": "Reference"
},
"widget-action": {
"header-button": "Widget header button",

6
ui-ngx/src/styles.scss

@ -921,6 +921,12 @@ mat-icon {
}
.mat-mdc-icon-button {
&.tb-mat-16 {
@include tb-mat-icon-button-size(16);
.mat-icon {
@include tb-mat-icon-size(16);
}
}
&.tb-mat-20 {
@include tb-mat-icon-button-size(20);
.mat-icon {

Loading…
Cancel
Save