UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

257 lines (250 loc) 22.9 kB
import * as i0 from '@angular/core'; import { Input, Directive, EventEmitter, ViewChild, ContentChildren, Output, Component, NgModule } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import * as i2 from '@c8y/ngx-components'; import { gettext, Status, C8yStepper, CoreModule } from '@c8y/ngx-components'; import * as i1 from '@c8y/ngx-components/operations/bulk-operations-service'; import * as i6 from '@c8y/ngx-components/operations/create-bulk-operation-details'; import { CreateBulkOperationDetailsComponent, CreateBulkOperationDetailsModule } from '@c8y/ngx-components/operations/create-bulk-operation-details'; import { BULK_OPERATION_EVENT } from '@c8y/ngx-components/operations/product-experience'; import { get } from 'lodash-es'; import * as i3 from '@angular/common'; import * as i4 from '@angular/cdk/stepper'; import * as i5 from '@c8y/ngx-components/operations/device-selector'; import { DeviceSelectorModule } from '@c8y/ngx-components/operations/device-selector'; import * as i7 from '@c8y/ngx-components/operations/operation-summary'; import { OperationSummaryModule } from '@c8y/ngx-components/operations/operation-summary'; class CustomStep { constructor(templateRef) { this.templateRef = templateRef; this.buttonsDisabled = false; this.onNext = ({ stepper, step }) => { // steps without own `onNext` handler, e.g. preview steps need to mark themselves as `completed`, // otherwise stepper will not allow to move forth from them as soon as the user navigates back // and the `c8y-stepper-buttons` component marks the step as incomplete. step.completed = true; stepper.next(); }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CustomStep, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: CustomStep, isStandalone: false, selector: "[customStep]", inputs: { label: ["customStep", "label"], completed: ["customStepCompleted", "completed"], buttonsDisabled: ["customStepButtonsDisabled", "buttonsDisabled"], onNext: ["customStepOnNext", "onNext"] }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CustomStep, decorators: [{ type: Directive, args: [{ selector: '[customStep]', standalone: false }] }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { label: [{ type: Input, args: ['customStep'] }], completed: [{ type: Input, args: ['customStepCompleted'] }], buttonsDisabled: [{ type: Input, args: ['customStepButtonsDisabled'] }], onNext: [{ type: Input, args: ['customStepOnNext'] }] } }); class BulkOperationStepper { constructor(bulkOperationService, modal, alert) { this.bulkOperationService = bulkOperationService; this.modal = modal; this.alert = alert; this.BULK_OPERATION_EVENT = BULK_OPERATION_EVENT; this.selectionChange = new EventEmitter(); this.steps = []; this.showStepper = false; this.showButtons = false; this.stepperButtonsLabels = { custom: gettext('Schedule') }; this.deviceTypesSubject$ = new Subject(); this.endSubscriptions = new Subject(); this.deviceTypes$ = this.deviceTypesSubject$.asObservable(); } ngAfterViewInit() { setTimeout(() => { // wait for the next event loop turn as `steps` has already been checked in this CD cycle this.steps = this.customSteps.toArray(); this.showStepper = true; setTimeout(() => { // postpone rendering of buttons for custom steps to the point where custom steps have already been rendered this.showButtons = true; if (this.stepper) { this.stepper.selectionChange.pipe(takeUntil(this.endSubscriptions)).subscribe(event => { this.selectionChange.next(event); }); this.operationDetailsForm = this.createBulkOperationDetailsComponent.fgOperationDescription; } }); }); } changeDeviceTypes(deviceTypes) { if (deviceTypes) { this.deviceTypesSubject$.next(Array.isArray(deviceTypes) ? deviceTypes : [deviceTypes]); } else { this.deviceTypesSubject$.next([]); } } async confirmDeviceSelection($event) { if (!this.deviceQueryString) { try { await this.modal.confirm(gettext('All devices selected'), gettext('You are about to schedule the bulk operation to be executed for all devices. Do you want to proceed?'), Status.WARNING, { ok: gettext('Schedule for all devices'), cancel: gettext('Cancel and select devices') }); $event.step.completed = true; $event.stepper.next(); this.operationDetails = this.retrieveOperationDetails ? await this.retrieveOperationDetails() : undefined; } catch (ex) { // Intentionally empty } } else { $event.step.completed = true; $event.stepper.next(); this.operationDetails = this.retrieveOperationDetails ? await this.retrieveOperationDetails() : undefined; } this.bulkOperationType = this.bulkOperationService.retrieveBulkOperationType(get(this.operationDetails, 'prototype')); if (this.operationDetailsForm && get(this.operationDetailsForm, 'controls.description.pristine') && this.operationDetails) { this.operationDetailsForm.patchValue({ description: get(this.operationDetails, 'prototype.description') }); } } cancel() { this.close(); } async scheduleBulkOperation() { this.pendingStatus = true; try { this.operationDetails.prototype.description = get(this.operationDetailsForm, 'controls.description.value'); this.operationDetails.note = get(this.operationDetailsForm, 'controls.note.value'); this.operationDetails.schedule = get(this.operationDetailsForm, 'controls.schedule.value'); await this.bulkOperationService.scheduleBulkOperation(this.deviceQueryString, this.operationDetails); this.alert.success(gettext('New bulk operation scheduled.')); this.close(); } catch (ex) { this.alert.addServerFailure(ex); } this.pendingStatus = false; } ngOnDestroy() { this.endSubscriptions.next(); this.endSubscriptions.complete(); } close() { this.stepper.reset(); this.bulkOperationService.returnToBulkOperationOverview(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepper, deps: [{ token: i1.BulkOperationsService }, { token: i2.ModalService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: BulkOperationStepper, isStandalone: false, selector: "c8y-bulk-operation-stepper", inputs: { type: "type" }, outputs: { selectionChange: "selectionChange" }, queries: [{ propertyName: "customSteps", predicate: CustomStep }], viewQueries: [{ propertyName: "stepper", first: true, predicate: C8yStepper, descendants: true }, { propertyName: "createBulkOperationDetailsComponent", first: true, predicate: CreateBulkOperationDetailsComponent, descendants: true }], ngImport: i0, template: "<div class=\"fit-h\">\n <c8y-stepper\n class=\"d-col no-align-items fit-h c8y-stepper--no-btns a-i-center\"\n linear\n [disableDefaultIcons]=\"{ edit: true, done: false }\"\n [customClasses]=\"['col-xs-10', 'col-sm-8', 'm-t-24', 'm-b-40', 'p-0', 'flex-no-shrink']\"\n *ngIf=\"showStepper\"\n c8yProductExperience\n [actionName]=\"BULK_OPERATION_EVENT\"\n [actionData]=\"{ bulkOperationType: type }\"\n >\n <!-- CUSTOM STEPS 1 to N-2 -->\n <cdk-step\n *ngFor=\"let step of steps\"\n [label]=\"step.label | translate\"\n [completed]=\"step.completed\"\n >\n <ng-container *ngTemplateOutlet=\"step.templateRef\"></ng-container>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n [disabled]=\"step.buttonsDisabled\"\n (onNext)=\"step.onNext($event)\"\n (onCancel)=\"cancel()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n <!-- STEP N-1 - Data-grid -->\n <cdk-step [label]=\"'Filter target devices' | translate\">\n <div class=\"card-block p-b-0 p-t-0 flex-no-shrink separator-bottom col-xs-12\">\n <div class=\"d-flex j-c-center p-b-8 p-t-4\">\n <div class=\"col-xs-12 col-sm-6\">\n <h4 class=\"text-center text-normal m-b-16\">\n {{ 'Filter target devices' | translate }}\n </h4>\n </div>\n </div>\n </div>\n\n <div class=\"col-xs-12 flex-grow no-gutter\">\n <c8y-device-selector\n [deviceTypes]=\"deviceTypes$\"\n (onDeviceQueryStringChange)=\"deviceQueryString = $event\"\n ></c8y-device-selector>\n </div>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n (onNext)=\"confirmDeviceSelection($event)\"\n (onCancel)=\"cancel()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n\n <!-- STEP N - Scheduler -->\n <cdk-step [label]=\"'Confirm and schedule bulk operation' | translate\">\n <div class=\"card-block flex-no-shrink p-b-0 p-t-0 separator-bottom col-xs-12\">\n <div class=\"d-flex j-c-center p-b-8 p-t-4\">\n <div class=\"col-xs-12 col-sm-6\">\n <h4 class=\"text-center text-normal m-b-16\">\n {{ 'Confirm and schedule bulk operation' | translate }}\n </h4>\n </div>\n </div>\n </div>\n\n <div class=\"col-xs-12 flex-grow no-gutter\">\n <div class=\"card-inner-scroll fit-h\">\n <div class=\"card-block p-b-0\">\n <div class=\"d-flex j-c-center p-t-8 p-b-8\">\n <div class=\"col-xs-12 col-sm-6\">\n <c8y-operation-summary\n [name]=\"operationDetails?.name | translate\"\n [description]=\"operationDetails?.description | translate\"\n [deviceQueryString]=\"deviceQueryString\"\n ></c8y-operation-summary>\n </div>\n </div>\n <div class=\"d-flex j-c-center\">\n <div class=\"col-xs-12 col-sm-6\">\n <c8y-create-bulk-operation-details\n [bulkOperationType]=\"bulkOperationType\"\n ></c8y-create-bulk-operation-details>\n </div>\n </div>\n </div>\n </div>\n </div>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n [labels]=\"stepperButtonsLabels\"\n [pending]=\"pendingStatus\"\n [disabled]=\"operationDetailsForm?.invalid\"\n (onCancel)=\"cancel()\"\n (onCustom)=\"scheduleBulkOperation()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n </c8y-stepper>\n</div>\n", dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i2.C8yStepper, selector: "c8y-stepper", inputs: ["disableDefaultIcons", "disableProgressButtons", "customClasses", "hideStepProgress", "useStepLabelsAsTitlesOnly"], outputs: ["onStepChange"] }, { kind: "component", type: i4.CdkStep, selector: "cdk-step", inputs: ["stepControl", "label", "errorMessage", "aria-label", "aria-labelledby", "state", "editable", "optional", "completed", "hasError"], outputs: ["interacted"], exportAs: ["cdkStep"] }, { kind: "component", type: i2.C8yStepperButtons, selector: "c8y-stepper-buttons", inputs: ["labels", "pending", "disabled", "showButtons"], outputs: ["onCancel", "onNext", "onBack", "onCustom"] }, { kind: "directive", type: i2.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i5.DeviceSelectorComponent, selector: "c8y-device-selector", inputs: ["deviceTypes"], outputs: ["onDeviceQueryStringChange"] }, { kind: "component", type: i6.CreateBulkOperationDetailsComponent, selector: "c8y-create-bulk-operation-details", inputs: ["bulkOperationType"] }, { kind: "component", type: i7.OperationSummaryComponent, selector: "c8y-operation-summary", inputs: ["name", "description", "deviceQueryString"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepper, decorators: [{ type: Component, args: [{ selector: 'c8y-bulk-operation-stepper', standalone: false, template: "<div class=\"fit-h\">\n <c8y-stepper\n class=\"d-col no-align-items fit-h c8y-stepper--no-btns a-i-center\"\n linear\n [disableDefaultIcons]=\"{ edit: true, done: false }\"\n [customClasses]=\"['col-xs-10', 'col-sm-8', 'm-t-24', 'm-b-40', 'p-0', 'flex-no-shrink']\"\n *ngIf=\"showStepper\"\n c8yProductExperience\n [actionName]=\"BULK_OPERATION_EVENT\"\n [actionData]=\"{ bulkOperationType: type }\"\n >\n <!-- CUSTOM STEPS 1 to N-2 -->\n <cdk-step\n *ngFor=\"let step of steps\"\n [label]=\"step.label | translate\"\n [completed]=\"step.completed\"\n >\n <ng-container *ngTemplateOutlet=\"step.templateRef\"></ng-container>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n [disabled]=\"step.buttonsDisabled\"\n (onNext)=\"step.onNext($event)\"\n (onCancel)=\"cancel()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n <!-- STEP N-1 - Data-grid -->\n <cdk-step [label]=\"'Filter target devices' | translate\">\n <div class=\"card-block p-b-0 p-t-0 flex-no-shrink separator-bottom col-xs-12\">\n <div class=\"d-flex j-c-center p-b-8 p-t-4\">\n <div class=\"col-xs-12 col-sm-6\">\n <h4 class=\"text-center text-normal m-b-16\">\n {{ 'Filter target devices' | translate }}\n </h4>\n </div>\n </div>\n </div>\n\n <div class=\"col-xs-12 flex-grow no-gutter\">\n <c8y-device-selector\n [deviceTypes]=\"deviceTypes$\"\n (onDeviceQueryStringChange)=\"deviceQueryString = $event\"\n ></c8y-device-selector>\n </div>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n (onNext)=\"confirmDeviceSelection($event)\"\n (onCancel)=\"cancel()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n\n <!-- STEP N - Scheduler -->\n <cdk-step [label]=\"'Confirm and schedule bulk operation' | translate\">\n <div class=\"card-block flex-no-shrink p-b-0 p-t-0 separator-bottom col-xs-12\">\n <div class=\"d-flex j-c-center p-b-8 p-t-4\">\n <div class=\"col-xs-12 col-sm-6\">\n <h4 class=\"text-center text-normal m-b-16\">\n {{ 'Confirm and schedule bulk operation' | translate }}\n </h4>\n </div>\n </div>\n </div>\n\n <div class=\"col-xs-12 flex-grow no-gutter\">\n <div class=\"card-inner-scroll fit-h\">\n <div class=\"card-block p-b-0\">\n <div class=\"d-flex j-c-center p-t-8 p-b-8\">\n <div class=\"col-xs-12 col-sm-6\">\n <c8y-operation-summary\n [name]=\"operationDetails?.name | translate\"\n [description]=\"operationDetails?.description | translate\"\n [deviceQueryString]=\"deviceQueryString\"\n ></c8y-operation-summary>\n </div>\n </div>\n <div class=\"d-flex j-c-center\">\n <div class=\"col-xs-12 col-sm-6\">\n <c8y-create-bulk-operation-details\n [bulkOperationType]=\"bulkOperationType\"\n ></c8y-create-bulk-operation-details>\n </div>\n </div>\n </div>\n </div>\n </div>\n <c8y-stepper-buttons\n class=\"d-block card-footer p-24 separator fit-w sticky-bottom bg-level-0\"\n *ngIf=\"showButtons\"\n [labels]=\"stepperButtonsLabels\"\n [pending]=\"pendingStatus\"\n [disabled]=\"operationDetailsForm?.invalid\"\n (onCancel)=\"cancel()\"\n (onCustom)=\"scheduleBulkOperation()\"\n ></c8y-stepper-buttons>\n </cdk-step>\n </c8y-stepper>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.BulkOperationsService }, { type: i2.ModalService }, { type: i2.AlertService }], propDecorators: { type: [{ type: Input }], selectionChange: [{ type: Output }], customSteps: [{ type: ContentChildren, args: [CustomStep] }], stepper: [{ type: ViewChild, args: [C8yStepper, { static: false }] }], createBulkOperationDetailsComponent: [{ type: ViewChild, args: [CreateBulkOperationDetailsComponent, { static: false }] }] } }); class BaseStepperComponent { constructor() { /** * A map holding step data. The order of properties need to match the order of * the steps they hold data for as the index of the property is used to clear * step data when navigating forth after changing data at an earlier step. */ this.stepData = {}; this.endSubscriptions = new Subject(); } set deviceTypes(deviceTypes) { if (this.operationStepper) { this.operationStepper.changeDeviceTypes(deviceTypes); } } ngOnInit() { this.operationStepper.retrieveOperationDetails = this.retrieveOperationPrototype.bind(this); this.operationStepper.selectionChange .pipe(takeUntil(this.endSubscriptions)) .subscribe(this.onSelectionChange.bind(this)); } ngOnDestroy() { this.endSubscriptions.next(); this.endSubscriptions.complete(); } onSelectionChange(event) { const { selectedIndex, previouslySelectedIndex } = event; if (selectedIndex > previouslySelectedIndex && selectedIndex < Object.keys(this.stepData).length) { // TODO clear step data only if previous step is "dirty" this.stepData[this.getStepDataKeyByIndex(selectedIndex)] = undefined; } } getStepDataKeyByIndex(index) { return Object.keys(this.stepData)[index]; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BaseStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: BaseStepperComponent, isStandalone: false, selector: "c8y-base-stepper", viewQueries: [{ propertyName: "operationStepper", first: true, predicate: BulkOperationStepper, descendants: true, static: true }], ngImport: i0, template: '', isInline: true }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BaseStepperComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-base-stepper', template: '', standalone: false }] }], propDecorators: { operationStepper: [{ type: ViewChild, args: [BulkOperationStepper, { static: true }] }] } }); /** * This module provides base stepper class and stepper wrapper component. */ class BulkOperationStepperModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepperModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepperModule, declarations: [BulkOperationStepper, CustomStep], imports: [CoreModule, DeviceSelectorModule, CreateBulkOperationDetailsModule, OperationSummaryModule], exports: [BulkOperationStepper, CustomStep] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepperModule, imports: [CoreModule, DeviceSelectorModule, CreateBulkOperationDetailsModule, OperationSummaryModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationStepperModule, decorators: [{ type: NgModule, args: [{ imports: [ CoreModule, DeviceSelectorModule, CreateBulkOperationDetailsModule, OperationSummaryModule ], declarations: [BulkOperationStepper, CustomStep], exports: [BulkOperationStepper, CustomStep] }] }] }); /** * Generated bundle index. Do not edit. */ export { BaseStepperComponent, BulkOperationStepper, BulkOperationStepperModule, CustomStep }; //# sourceMappingURL=c8y-ngx-components-operations-bulk-operation-stepper.mjs.map