Browse Source

Merge pull request #9467 from vvlladd28/widget-bundle/add-widget-inside

Add support added new widgets inside widget bundle
pull/9468/head
Igor Kulikov 3 years ago
committed by GitHub
parent
commit
bdcd8fd7f6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      ui-ngx/src/app/core/http/widget.service.ts
  2. 6
      ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts
  3. 14
      ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts
  4. 26
      ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html
  5. 61
      ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts
  6. 4
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  7. 6
      ui-ngx/src/typings/utils.d.ts

9
ui-ngx/src/app/core/http/widget.service.ts

@ -236,6 +236,15 @@ export class WidgetService {
return this.http.get<PageData<WidgetTypeInfo>>(url, defaultHttpOptionsFromConfig(config));
}
public addWidgetFqnToWidgetBundle(widgetsBundleId: string, fqn: string, config?: RequestConfig) {
return this.getBundleWidgetTypeFqns(widgetsBundleId, config).pipe(
mergeMap(widgetsBundleFqn => {
widgetsBundleFqn.push(fqn);
return this.updateWidgetsBundleWidgetFqns(widgetsBundleId, widgetsBundleFqn, config);
})
);
}
public getWidgetTemplate(widgetTypeParam: widgetType,
config?: RequestConfig): Observable<WidgetInfo> {
const templateWidgetType = widgetTypesData.get(widgetTypeParam);

6
ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts

@ -297,7 +297,7 @@ export class ImportExportService {
);
}
public importWidgetType(): Observable<WidgetType> {
public importWidgetType(): Observable<WidgetTypeDetails> {
return this.openImportDialog('widget.import', 'widget-type.widget-file').pipe(
mergeMap((widgetTypeDetails: WidgetTypeDetails) => {
if (!this.validateImportedWidgetTypeDetails(widgetTypeDetails)) {
@ -309,9 +309,7 @@ export class ImportExportService {
return this.widgetService.saveImportedWidgetTypeDetails(widgetTypeDetails);
}
}),
catchError((err) => {
return of(null);
})
catchError(() => of(null))
);
}

14
ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts

@ -52,7 +52,7 @@ import {
SaveWidgetTypeAsDialogComponent,
SaveWidgetTypeAsDialogResult
} from '@home/pages/widget/save-widget-type-as-dialog.component';
import { forkJoin, Subscription } from 'rxjs';
import { forkJoin, mergeMap, of, Subscription } from 'rxjs';
import { ResizeObserver } from '@juggle/resize-observer';
import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models';
import { Observable } from 'rxjs/internal/Observable';
@ -563,7 +563,17 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
private commitSaveWidget() {
const id = (this.widgetTypeDetails && this.widgetTypeDetails.id) ? this.widgetTypeDetails.id : undefined;
const createdTime = (this.widgetTypeDetails && this.widgetTypeDetails.createdTime) ? this.widgetTypeDetails.createdTime : undefined;
this.widgetService.saveWidgetTypeDetails(this.widget, id, createdTime).subscribe({
this.widgetService.saveWidgetTypeDetails(this.widget, id, createdTime).pipe(
mergeMap((widgetTypeDetails) => {
const widgetsBundleId = this.route.snapshot.params.widgetsBundleId as string;
if (widgetsBundleId && !id) {
return this.widgetService.addWidgetFqnToWidgetBundle(widgetsBundleId, widgetTypeDetails.fqn).pipe(
map(() => widgetTypeDetails)
);
}
return of(widgetTypeDetails);
})
).subscribe({
next: (widgetTypeDetails) => {
this.saveWidgetPending = false;
if (!this.widgetTypeDetails?.id) {

26
ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html

@ -27,6 +27,23 @@
</button>
<span class="mat-headline-5">{{ widgetsBundle.title }}: {{ 'widget.widgets' | translate }}</span>
<span fxFlex></span>
<button mat-icon-button [disabled]="isLoading$ | async"
*ngIf="!isReadOnly"
matTooltip="{{ 'widget.add-new-widget' | translate }}"
matTooltipPosition="above"
[matMenuTriggerFor]="addWidgetMenu">
<mat-icon>add</mat-icon>
</button>
<mat-menu #addWidgetMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="addWidgetType($event)">
<mat-icon>insert_drive_file</mat-icon>
<span>{{ 'dashboard.create-new-widget' | translate }}</span>
</button>
<button mat-menu-item (click)="importWidgetType()">
<mat-icon>file_upload</mat-icon>
<span>{{ 'widget.import' | translate }}</span>
</button>
</mat-menu>
<button mat-icon-button
matTooltip="{{ 'widgets-bundle.export' | translate }}"
matTooltipPosition="above"
@ -83,18 +100,15 @@
</div>
</div>
<div *ngIf="editMode && !addMode && widgets?.length" class="tb-add-widget-button"
matTooltip="{{ 'widget.add' | translate }}"
matTooltip="{{ 'widget.add-existing-widget' | translate }}"
matTooltipPosition="above"
(click)="addWidgetMode()">
<tb-icon color="primary" class="tb-add-widget-icon">add</tb-icon>
</div>
<div *ngIf="editMode && !addMode && !widgets?.length" class="tb-add-widget-button-panel">
<div class="tb-add-widget-button-with-text"
matTooltip="{{ 'widget.add' | translate }}"
matTooltipPosition="above"
(click)="addWidgetMode()">
<div class="tb-add-widget-button-with-text" (click)="addWidgetMode()">
<tb-icon color="primary" class="tb-add-widget-icon">add</tb-icon>
<div class="tb-add-widget-button-text" translate>widget.add</div>
<div class="tb-add-widget-button-text" translate>widget.add-existing-widget</div>
</div>
</div>
<div *ngIf="isReadOnly && !widgets?.length" class="tb-no-data-available">

61
ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts

@ -24,13 +24,17 @@ import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { WidgetsBundle } from '@shared/models/widgets-bundle.model';
import { WidgetTypeInfo } from '@shared/models/widget.models';
import { widgetType as WidgetDataType, WidgetTypeInfo } from '@shared/models/widget.models';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { ImportExportService } from '@home/components/import-export/import-export.service';
import { WidgetService } from '@core/http/widget.service';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { isDefinedAndNotNull } from '@core/utils';
import { FormControl, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { SelectWidgetTypeDialogComponent } from '@home/pages/widget/select-widget-type-dialog.component';
type WidgetTypeBundle = WithOptional<WidgetTypeInfo, 'widgetType'>;
@Component({
selector: 'tb-widgets-bundle-widget',
@ -47,7 +51,7 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
isDirty = false;
widgetsBundle: WidgetsBundle;
widgets: Array<WidgetTypeInfo>;
widgets: Array<WidgetTypeBundle>;
excludeWidgetTypeIds: Array<string>;
addWidgetFormControl = new FormControl(null, [Validators.required]);
@ -58,7 +62,8 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
private widgetsService: WidgetService,
private importExport: ImportExportService,
private sanitizer: DomSanitizer,
private cd: ChangeDetectorRef) {
private cd: ChangeDetectorRef,
private dialog: MatDialog) {
super(store);
this.authUser = getCurrentAuthUser(this.store);
this.widgetsBundle = this.route.snapshot.data.widgetsBundle;
@ -88,7 +93,7 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
return '/assets/widget-preview-empty.svg';
}
trackByWidget(index: number, widget: WidgetTypeInfo): any {
trackByWidget(index: number, widget: WidgetTypeBundle): any {
return widget;
}
@ -109,27 +114,27 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
this.addMode = false;
}
private addWidget(newWidget: WidgetTypeInfo) {
private addWidget(newWidget: WidgetTypeBundle) {
this.widgets.push(newWidget);
this.isDirty = true;
this.addMode = false;
}
openWidgetEditor($event: Event, widgetType: WidgetTypeInfo) {
openWidgetEditor($event: Event, widgetType: WidgetTypeBundle) {
if ($event) {
$event.stopPropagation();
}
this.router.navigate([widgetType.id.id], {relativeTo: this.route}).then(()=> {});
}
exportWidgetType($event: Event, widgetType: WidgetTypeInfo) {
exportWidgetType($event: Event, widgetType: WidgetTypeBundle) {
if ($event) {
$event.stopPropagation();
}
this.importExport.exportWidgetType(widgetType.id.id);
}
removeWidgetType($event: Event, widgetType: WidgetTypeInfo) {
removeWidgetType($event: Event, widgetType: WidgetTypeBundle) {
if ($event) {
$event.stopPropagation();
}
@ -176,4 +181,44 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
});
}
addWidgetType($event: Event): void {
if ($event) {
$event.stopPropagation();
}
this.dialog.open<SelectWidgetTypeDialogComponent, any,
WidgetDataType>(SelectWidgetTypeDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog']
}).afterClosed().subscribe(
(type) => {
if (type) {
this.router.navigate([type], {relativeTo: this.route}).then(() => {});
}
}
);
}
importWidgetType() {
this.importExport.importWidgetType().subscribe(
(widgetType) => {
if (widgetType) {
const isExistWidget = this.widgets.some(widget => widget.id.id === widgetType.id.id);
if (isExistWidget) {
this.widgets = this.widgets.map(widget => widget.id.id !== widgetType.id.id ? widget : widgetType);
}
if (this.editMode) {
this.widgets.push(widgetType);
this.isDirty = true;
this.cd.markForCheck();
} else if (!isExistWidget) {
this.widgetsService.addWidgetFqnToWidgetBundle(this.widgetsBundle.id.id, widgetType.fqn).subscribe(() => {
this.widgets.push(widgetType);
this.cd.markForCheck();
});
}
}
}
);
}
}

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

@ -4759,7 +4759,7 @@
"no-widgets-text": "No widgets found",
"management": "Widget management",
"editor": "Widget Editor",
"confirm-to-exit-editor-html": "You have unsaved default widget settings.<br>Are you sure you want to leave this page?",
"confirm-to-exit-editor-html": "You have unsaved widget settings.<br>Are you sure you want to leave this page?",
"widget-type-not-found": "Problem loading widget configuration.<br>Probably associated\n widget type was removed.",
"widget-type-load-error": "Widget wasn't loaded due to the following errors:",
"remove": "Remove widget",
@ -4827,6 +4827,8 @@
"details": "Details",
"widget-details": "Widget details",
"add": "Add Widget",
"add-existing-widget": "Add existing widget",
"add-new-widget": "Add new widget",
"search-widgets": "Search widgets",
"selected-widgets": "{ count, plural, =1 {1 widget} other {# widgets} } selected",
"undo": "Undo widget changes",

6
ui-ngx/src/typings/utils.d.ts

@ -19,3 +19,9 @@ type NestedKeyOf<ObjectType extends object> =
? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]> extends infer U extends string ? U : never}`
: `${Key}`
}[keyof ObjectType & (string | number)];
type AllKeyOf<T> = T extends never ? never : keyof T;
type Optional<T, K> = { [P in Extract<keyof T, K>]?: T[P] };
type WithOptional<T, K extends AllKeyOf<T>> = T extends never ? never : Omit<T, K> & Optional<T, K>;

Loading…
Cancel
Save