UI: Add support inside widget bundle added new widgets
This commit is contained in:
parent
f03751366b
commit
deb8cf3a22
@ -236,6 +236,15 @@ export class WidgetService {
|
|||||||
return this.http.get<PageData<WidgetTypeInfo>>(url, defaultHttpOptionsFromConfig(config));
|
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,
|
public getWidgetTemplate(widgetTypeParam: widgetType,
|
||||||
config?: RequestConfig): Observable<WidgetInfo> {
|
config?: RequestConfig): Observable<WidgetInfo> {
|
||||||
const templateWidgetType = widgetTypesData.get(widgetTypeParam);
|
const templateWidgetType = widgetTypesData.get(widgetTypeParam);
|
||||||
|
|||||||
@ -297,7 +297,7 @@ export class ImportExportService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public importWidgetType(): Observable<WidgetType> {
|
public importWidgetType(): Observable<WidgetTypeDetails> {
|
||||||
return this.openImportDialog('widget-type.import', 'widget-type.widget-type-file').pipe(
|
return this.openImportDialog('widget-type.import', 'widget-type.widget-type-file').pipe(
|
||||||
mergeMap((widgetTypeDetails: WidgetTypeDetails) => {
|
mergeMap((widgetTypeDetails: WidgetTypeDetails) => {
|
||||||
if (!this.validateImportedWidgetTypeDetails(widgetTypeDetails)) {
|
if (!this.validateImportedWidgetTypeDetails(widgetTypeDetails)) {
|
||||||
@ -309,9 +309,7 @@ export class ImportExportService {
|
|||||||
return this.widgetService.saveImportedWidgetTypeDetails(widgetTypeDetails);
|
return this.widgetService.saveImportedWidgetTypeDetails(widgetTypeDetails);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
catchError((err) => {
|
catchError(() => of(null))
|
||||||
return of(null);
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,11 +52,11 @@ import {
|
|||||||
SaveWidgetTypeAsDialogComponent,
|
SaveWidgetTypeAsDialogComponent,
|
||||||
SaveWidgetTypeAsDialogResult
|
SaveWidgetTypeAsDialogResult
|
||||||
} from '@home/pages/widget/save-widget-type-as-dialog.component';
|
} from '@home/pages/widget/save-widget-type-as-dialog.component';
|
||||||
import { forkJoin, Subscription } from 'rxjs';
|
import { forkJoin, mergeMap, of, Subscription, throwError } from 'rxjs';
|
||||||
import { ResizeObserver } from '@juggle/resize-observer';
|
import { ResizeObserver } from '@juggle/resize-observer';
|
||||||
import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models';
|
import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { map, tap } from 'rxjs/operators';
|
import { catchError, map, tap } from 'rxjs/operators';
|
||||||
import { beautifyCss, beautifyHtml, beautifyJs } from '@shared/models/beautify.models';
|
import { beautifyCss, beautifyHtml, beautifyJs } from '@shared/models/beautify.models';
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
|
||||||
@ -543,7 +543,20 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
|
|||||||
private commitSaveWidget() {
|
private commitSaveWidget() {
|
||||||
const id = (this.widgetTypeDetails && this.widgetTypeDetails.id) ? this.widgetTypeDetails.id : undefined;
|
const id = (this.widgetTypeDetails && this.widgetTypeDetails.id) ? this.widgetTypeDetails.id : undefined;
|
||||||
const createdTime = (this.widgetTypeDetails && this.widgetTypeDetails.createdTime) ? this.widgetTypeDetails.createdTime : 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) {
|
||||||
|
return this.widgetService.addWidgetFqnToWidgetBundle(widgetsBundleId, widgetTypeDetails.fqn).pipe(
|
||||||
|
map(() => widgetTypeDetails),
|
||||||
|
catchError((error) => this.widgetService.deleteWidgetType(widgetTypeDetails.id.id).pipe(
|
||||||
|
mergeMap(() => throwError(() => error))
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return of(widgetTypeDetails);
|
||||||
|
})
|
||||||
|
).subscribe({
|
||||||
next: (widgetTypeDetails) => {
|
next: (widgetTypeDetails) => {
|
||||||
this.saveWidgetPending = false;
|
this.saveWidgetPending = false;
|
||||||
if (!this.widgetTypeDetails?.id) {
|
if (!this.widgetTypeDetails?.id) {
|
||||||
|
|||||||
@ -27,6 +27,23 @@
|
|||||||
</button>
|
</button>
|
||||||
<span class="mat-headline-5">{{ widgetsBundle.title }}: {{ 'widget.widgets' | translate }}</span>
|
<span class="mat-headline-5">{{ widgetsBundle.title }}: {{ 'widget.widgets' | translate }}</span>
|
||||||
<span fxFlex></span>
|
<span fxFlex></span>
|
||||||
|
<button mat-icon-button [disabled]="isLoading$ | async"
|
||||||
|
*ngIf="editMode"
|
||||||
|
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
|
<button mat-icon-button
|
||||||
matTooltip="{{ 'widgets-bundle.export' | translate }}"
|
matTooltip="{{ 'widgets-bundle.export' | translate }}"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
@ -83,18 +100,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="editMode && !addMode && widgets?.length" class="tb-add-widget-button"
|
<div *ngIf="editMode && !addMode && widgets?.length" class="tb-add-widget-button"
|
||||||
matTooltip="{{ 'widget.add' | translate }}"
|
matTooltip="{{ 'widget.add-existing-widget' | translate }}"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
(click)="addWidgetMode()">
|
(click)="addWidgetMode()">
|
||||||
<tb-icon color="primary" class="tb-add-widget-icon">add</tb-icon>
|
<tb-icon color="primary" class="tb-add-widget-icon">add</tb-icon>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="editMode && !addMode && !widgets?.length" class="tb-add-widget-button-panel">
|
<div *ngIf="editMode && !addMode && !widgets?.length" class="tb-add-widget-button-panel">
|
||||||
<div class="tb-add-widget-button-with-text"
|
<div class="tb-add-widget-button-with-text" (click)="addWidgetMode()">
|
||||||
matTooltip="{{ 'widget.add' | translate }}"
|
|
||||||
matTooltipPosition="above"
|
|
||||||
(click)="addWidgetMode()">
|
|
||||||
<tb-icon color="primary" class="tb-add-widget-icon">add</tb-icon>
|
<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>
|
</div>
|
||||||
<div *ngIf="isReadOnly && !widgets?.length" class="tb-no-data-available">
|
<div *ngIf="isReadOnly && !widgets?.length" class="tb-no-data-available">
|
||||||
|
|||||||
@ -24,13 +24,17 @@ import { getCurrentAuthUser } from '@core/auth/auth.selectors';
|
|||||||
import { Authority } from '@shared/models/authority.enum';
|
import { Authority } from '@shared/models/authority.enum';
|
||||||
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
||||||
import { WidgetsBundle } from '@shared/models/widgets-bundle.model';
|
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 { CdkDragDrop } from '@angular/cdk/drag-drop';
|
||||||
import { ImportExportService } from '@home/components/import-export/import-export.service';
|
import { ImportExportService } from '@home/components/import-export/import-export.service';
|
||||||
import { WidgetService } from '@core/http/widget.service';
|
import { WidgetService } from '@core/http/widget.service';
|
||||||
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||||
import { isDefinedAndNotNull } from '@core/utils';
|
import { isDefinedAndNotNull } from '@core/utils';
|
||||||
import { FormControl, Validators } from '@angular/forms';
|
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({
|
@Component({
|
||||||
selector: 'tb-widgets-bundle-widget',
|
selector: 'tb-widgets-bundle-widget',
|
||||||
@ -47,7 +51,7 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
|
|||||||
isDirty = false;
|
isDirty = false;
|
||||||
|
|
||||||
widgetsBundle: WidgetsBundle;
|
widgetsBundle: WidgetsBundle;
|
||||||
widgets: Array<WidgetTypeInfo>;
|
widgets: Array<WidgetTypeBundle>;
|
||||||
excludeWidgetTypeIds: Array<string>;
|
excludeWidgetTypeIds: Array<string>;
|
||||||
|
|
||||||
addWidgetFormControl = new FormControl(null, [Validators.required]);
|
addWidgetFormControl = new FormControl(null, [Validators.required]);
|
||||||
@ -58,7 +62,8 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
|
|||||||
private widgetsService: WidgetService,
|
private widgetsService: WidgetService,
|
||||||
private importExport: ImportExportService,
|
private importExport: ImportExportService,
|
||||||
private sanitizer: DomSanitizer,
|
private sanitizer: DomSanitizer,
|
||||||
private cd: ChangeDetectorRef) {
|
private cd: ChangeDetectorRef,
|
||||||
|
private dialog: MatDialog) {
|
||||||
super(store);
|
super(store);
|
||||||
this.authUser = getCurrentAuthUser(this.store);
|
this.authUser = getCurrentAuthUser(this.store);
|
||||||
this.widgetsBundle = this.route.snapshot.data.widgetsBundle;
|
this.widgetsBundle = this.route.snapshot.data.widgetsBundle;
|
||||||
@ -88,7 +93,7 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
|
|||||||
return '/assets/widget-preview-empty.svg';
|
return '/assets/widget-preview-empty.svg';
|
||||||
}
|
}
|
||||||
|
|
||||||
trackByWidget(index: number, widget: WidgetTypeInfo): any {
|
trackByWidget(index: number, widget: WidgetTypeBundle): any {
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,27 +114,27 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn
|
|||||||
this.addMode = false;
|
this.addMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private addWidget(newWidget: WidgetTypeInfo) {
|
private addWidget(newWidget: WidgetTypeBundle) {
|
||||||
this.widgets.push(newWidget);
|
this.widgets.push(newWidget);
|
||||||
this.isDirty = true;
|
this.isDirty = true;
|
||||||
this.addMode = false;
|
this.addMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
openWidgetEditor($event: Event, widgetType: WidgetTypeInfo) {
|
openWidgetEditor($event: Event, widgetType: WidgetTypeBundle) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
this.router.navigate([widgetType.id.id], {relativeTo: this.route}).then(()=> {});
|
this.router.navigate([widgetType.id.id], {relativeTo: this.route}).then(()=> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
exportWidgetType($event: Event, widgetType: WidgetTypeInfo) {
|
exportWidgetType($event: Event, widgetType: WidgetTypeBundle) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
this.importExport.exportWidgetType(widgetType.id.id);
|
this.importExport.exportWidgetType(widgetType.id.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeWidgetType($event: Event, widgetType: WidgetTypeInfo) {
|
removeWidgetType($event: Event, widgetType: WidgetTypeBundle) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
@ -176,4 +181,37 @@ 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) {
|
||||||
|
if (this.widgets.some(widget => widget.id.id === widgetType.id.id)) {
|
||||||
|
this.widgets = this.widgets.map(widget => widget.id.id !== widgetType.id.id ? widget : widgetType);
|
||||||
|
} else {
|
||||||
|
this.widgets.push(widgetType);
|
||||||
|
}
|
||||||
|
this.isDirty = true;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4828,6 +4828,8 @@
|
|||||||
"details": "Details",
|
"details": "Details",
|
||||||
"widget-type-details": "Widget type details",
|
"widget-type-details": "Widget type details",
|
||||||
"add": "Add Widget",
|
"add": "Add Widget",
|
||||||
|
"add-existing-widget": "Add existing widget",
|
||||||
|
"add-new-widget": "Add new widget",
|
||||||
"no-widget-types-text": "No widget types found",
|
"no-widget-types-text": "No widget types found",
|
||||||
"search-widget-types": "Search widget types",
|
"search-widget-types": "Search widget types",
|
||||||
"selected-widget-types": "{ count, plural, =1 {1 widget type} other {# widget types} } selected",
|
"selected-widget-types": "{ count, plural, =1 {1 widget type} other {# widget types} } selected",
|
||||||
|
|||||||
6
ui-ngx/src/typings/utils.d.ts
vendored
6
ui-ngx/src/typings/utils.d.ts
vendored
@ -19,3 +19,9 @@ type NestedKeyOf<ObjectType extends object> =
|
|||||||
? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]> extends infer U extends string ? U : never}`
|
? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]> extends infer U extends string ? U : never}`
|
||||||
: `${Key}`
|
: `${Key}`
|
||||||
}[keyof ObjectType & (string | number)];
|
}[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…
x
Reference in New Issue
Block a user