@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
255 lines (248 loc) • 28 kB
JavaScript
import { NgIf, NgStyle, NgClass, NgForOf, AsyncPipe } from '@angular/common';
import * as i0 from '@angular/core';
import { Injectable, ViewChildren, Input, Optional, Component } from '@angular/core';
import * as i1$1 from '@angular/forms';
import { Validators, NgForm, ControlContainer, ReactiveFormsModule } from '@angular/forms';
import { gettext } from '@c8y/ngx-components/gettext';
import * as i2 from '@c8y/ngx-components';
import { C8yValidators, FormGroupComponent, MessagesComponent, MessageDirective, DropAreaComponent, LoadingComponent, C8yTranslatePipe, EmptyStateComponent } from '@c8y/ngx-components';
import * as i4 from '@c8y/ngx-components/context-dashboard';
import { get } from 'lodash-es';
import { BehaviorSubject, Subject, merge } from 'rxjs';
import { filter, distinctUntilChanged, tap, switchMap, map, shareReplay, takeUntil } from 'rxjs/operators';
import * as i1 from '@c8y/client';
import * as i3 from '@ngx-translate/core';
const defaultObjectFitValue = 'contain';
const defaultObjectPositionValue = 'center';
class ImageWidgetService {
constructor(inventory, fileService, alert, translate, binary) {
this.inventory = inventory;
this.fileService = fileService;
this.alert = alert;
this.translate = translate;
this.binary = binary;
}
async getImageDetails(imageBinaryId) {
if (!imageBinaryId) {
return null;
}
try {
const { data: imageBinaryMo } = await this.inventory.detail(imageBinaryId);
const file = await this.fileService.getFile(imageBinaryMo);
const base64 = await this.fileService.toBase64(file);
return {
file,
base64: base64,
c8y_SHA256: imageBinaryMo.c8y_SHA256
};
}
catch (e) {
const text = this.translate.instant(gettext('Unable to retrieve image with id: {{ imageBinaryId }}'), { imageBinaryId });
this.alert.danger(text, e?.data);
}
return null;
}
async uploadFile(file, options = {}) {
const hash = await this.fileService.getHashSumOfFile(file);
const fileDetails = { c8y_SHA256: hash };
const globalImage = !options?.dashboardMoId || options?.isDeviceTypeDashboard;
const partialBinaryMo = !globalImage
? { ...fileDetails }
: { ...fileDetails, c8y_Global: {} };
const { data: mo } = await this.binary.create(file, partialBinaryMo);
if (options?.dashboardMoId) {
await this.inventory.childAdditionsAdd(mo, options?.dashboardMoId);
}
return mo.id;
}
getStyling(config) {
if (!config.styling?.objectFit || config.styling?.objectFit === 'full-width') {
return null;
}
return {
'object-fit': config.styling.objectFit,
'object-position': `${config.styling?.objectPositionX || defaultObjectPositionValue} ${config.styling?.objectPositionY || defaultObjectPositionValue}`
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ImageWidgetService, deps: [{ token: i1.InventoryService }, { token: i2.FilesService }, { token: i2.AlertService }, { token: i3.TranslateService }, { token: i1.InventoryBinaryService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ImageWidgetService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ImageWidgetService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i1.InventoryService }, { type: i2.FilesService }, { type: i2.AlertService }, { type: i3.TranslateService }, { type: i1.InventoryBinaryService }] });
class ImageWidgetConfigComponent {
constructor(formBuilder, form, fileService, alert, imageWidget, widgetConfig, widgetConfigService) {
this.formBuilder = formBuilder;
this.form = form;
this.fileService = fileService;
this.alert = alert;
this.imageWidget = imageWidget;
this.widgetConfig = widgetConfig;
this.widgetConfigService = widgetConfigService;
this.imageBinaryId$ = new BehaviorSubject(null);
this.loading = false;
this.destroyed$ = new Subject();
this.objectFitOptions = [
{
label: gettext('Contain`verb, image fitting option`'),
value: 'contain',
description: gettext('The image is entirely displayed within the widget while preserving the aspect ratio.')
},
{
label: gettext('Cover`verb, image fitting option`'),
value: 'cover',
description: gettext('The image is resized to fill the widget while preserving the aspect ratio. Overflowing areas are clipped.')
},
{
label: gettext('Fill`verb, image fitting option`'),
value: 'fill',
description: gettext('The image is stretched to fill the widget, overriding the aspect-ratio.')
},
{
label: gettext('Full width`image fitting option`'),
value: 'full-width',
description: gettext(`The image is resized to fit the widget's width while preserving the aspect ratio. Overflowing area is scrollable.`)
}
];
}
async onBeforeSave(config) {
if (this.formGroup.invalid) {
return false;
}
const fileFromForm = this.getFileFromFormValue(this.formGroup.value);
if (fileFromForm && fileFromForm !== this.fileFromConfig) {
try {
const imageBinaryId = await this.imageWidget.uploadFile(fileFromForm, {
dashboardMoId: this.getDashboardMoId(),
isDeviceTypeDashboard: this.widgetConfig?.isDeviceTypeDashboard
});
Object.assign(config, { imageBinaryId });
}
catch (e) {
this.alert.danger(gettext('Unable to upload image.'), e?.data);
return false;
}
}
const styling = this.formGroup.value.styling;
Object.assign(config, { styling });
return true;
}
ngOnInit() {
this.initForm();
const imageFromConfig = this.imageBinaryId$.pipe(filter(id => !!id), distinctUntilChanged(), tap(() => (this.loading = true)), switchMap(imageBinaryId => this.imageWidget.getImageDetails(imageBinaryId)), tap(details => {
this.loading = false;
this.fileFromConfig = details.file;
if (details) {
this.formGroup.patchValue({ images: [{ file: details.file, name: details.file.name }] });
}
}), map(details => details?.base64), shareReplay(1));
const selectedFile = this.formGroup.valueChanges.pipe(map(value => this.getFileFromFormValue(value)), distinctUntilChanged(), switchMap(file => (file ? this.fileService.toBase64(file) : Promise.resolve(''))));
this.imageSrc$ = merge(imageFromConfig, selectedFile).pipe(map(base64 => (base64 ? base64 : '')));
this.imageBinaryId$.next(this.config?.imageBinaryId);
}
ngAfterViewInit() {
this.imagePreviewTemplate.changes.pipe(takeUntil(this.destroyed$)).subscribe(template => {
this.widgetConfigService.setPreview(template.first);
});
}
ngOnDestroy() {
this.destroyed$.next();
this.destroyed$.complete();
}
getDashboardMoId() {
return get(this.widgetConfig, 'mo.id', null);
}
async initForm() {
const stylingFormGroup = this.formBuilder.group({
objectFit: [
// fallback to 'full-width' for old legacy widgets, newly created widgets should use defaultObjectFitValue
this.config.imageBinaryId && !this.config.styling ? 'full-width' : defaultObjectFitValue,
[Validators.required]
],
objectPositionX: [defaultObjectPositionValue, [Validators.required]],
objectPositionY: [defaultObjectPositionValue, [Validators.required]]
});
this.formGroup = this.formBuilder.group({
images: [
null,
[
Validators.required,
Validators.minLength(1),
Validators.maxLength(1),
C8yValidators.filesValidator({ maximumFileSizeInKb: 1000, typePrefix: 'image/' })
]
],
styling: stylingFormGroup
});
this.form.form.addControl('config', this.formGroup);
this.formGroup.patchValue(this.config);
this.formGroup.valueChanges
.pipe(takeUntil(this.destroyed$))
.subscribe(changes => this.setStyling(changes));
}
getFileFromFormValue(formValue) {
const images = formValue?.images || [];
return images[0]?.file || null;
}
setStyling(config) {
this.styling = this.imageWidget.getStyling(config);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ImageWidgetConfigComponent, deps: [{ token: i1$1.FormBuilder }, { token: i1$1.NgForm }, { token: i2.FilesService }, { token: i2.AlertService }, { token: ImageWidgetService }, { token: i4.WidgetConfigComponent, optional: true }, { token: i4.WidgetConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ImageWidgetConfigComponent, isStandalone: true, selector: "c8y-image-widget-config", inputs: { config: "config" }, viewQueries: [{ propertyName: "imagePreviewTemplate", predicate: ["imagePreview"], descendants: true }], ngImport: i0, template: "<div [formGroup]=\"formGroup\">\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Image' | translate }}</legend>\n <c8y-form-group class=\"m-b-16\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n [icon]=\"'upload'\"\n formControlName=\"images\"\n [accept]=\"'image'\"\n [maxAllowedFiles]=\"1\"\n ></c8y-drop-area>\n <c8y-messages>\n <c8y-message\n name=\"maxFileSizeReached\"\n [text]=\"\n 'The maximum image size is {{ maxFileSize }} kB. The selected image has a size of {{ actualFileSize }} kB.'\n | translate\n \"\n ></c8y-message>\n <c8y-message\n name=\"wrongFileType\"\n [text]=\"'Wrong file type, select an image.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"maxlength\"\n [text]=\"'Only select one image.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"required\"\n [text]=\"'An image is required.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"minlength\"\n [text]=\"'An image is required.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </fieldset>\n\n <div *ngIf=\"imageSrc$ | async as src\">\n <fieldset class=\"c8y-fieldset\">\n <legend>\n {{ 'Size and alignment' | translate }}\n </legend>\n <div [formGroupName]=\"'styling'\">\n <c8y-form-group class=\"form-group-sm m-b-0\">\n <label class=\"m-b-4\">\n {{ 'Image display' | translate }}\n </label>\n <ul class=\"list-group separator-top-bottom\">\n <li\n class=\"list-group-item d-flex a-i-center p-l-0\"\n *ngFor=\"let objectFitOption of objectFitOptions; let i = index\"\n >\n <label class=\"c8y-radio\">\n <input\n type=\"radio\"\n [id]=\"'groupradiocontentclass' + i\"\n formControlName=\"objectFit\"\n [value]=\"objectFitOption.value\"\n />\n <span></span>\n <span class=\"l-h-1\">\n {{ objectFitOption.label | translate }}\n <br />\n <small class=\"text-muted\">\n {{ objectFitOption.description | translate }}\n </small>\n </span>\n </label>\n </li>\n </ul>\n </c8y-form-group>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <c8y-form-group class=\"form-group-sm\">\n <label>{{ 'Horizontal alignment' | translate }}</label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n formControlName=\"objectPositionX\"\n >\n <option [ngValue]=\"'left'\">\n {{ 'left`horizontal alignment`' | translate }}\n </option>\n <option [ngValue]=\"'center'\">\n {{ 'center`horizontal alignment`' | translate }}\n </option>\n <option [ngValue]=\"'right'\">\n {{ 'right`horizontal alignment`' | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n </div>\n <div class=\"col-md-6\">\n <c8y-form-group class=\"form-group-sm\">\n <label>{{ 'Vertical alignment' | translate }}</label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n formControlName=\"objectPositionY\"\n >\n <option [ngValue]=\"'top'\">\n {{ 'top`vertical alignment`' | translate }}\n </option>\n <option [ngValue]=\"'center'\">\n {{ 'center`vertical alignment`' | translate }}\n </option>\n <option [ngValue]=\"'bottom'\">\n {{ 'bottom`vertical alignment`' | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n </div>\n </div>\n </div>\n </fieldset>\n <ng-template #imagePreview>\n <img\n [ngStyle]=\"styling\"\n [src]=\"src\"\n [ngClass]=\"styling ? 'fit-h fit-w' : 'img-responsive'\"\n />\n </ng-template>\n </div>\n <div\n class=\"d-flex j-c-center\"\n *ngIf=\"loading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "maxFileSizeInMegaBytes", "accept"], outputs: ["dropped"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ImageWidgetConfigComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-image-widget-config', viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], standalone: true, imports: [
ReactiveFormsModule,
FormGroupComponent,
MessagesComponent,
MessageDirective,
C8yTranslatePipe,
AsyncPipe,
NgIf,
NgStyle,
NgClass,
NgForOf,
DropAreaComponent,
LoadingComponent
], template: "<div [formGroup]=\"formGroup\">\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Image' | translate }}</legend>\n <c8y-form-group class=\"m-b-16\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n [icon]=\"'upload'\"\n formControlName=\"images\"\n [accept]=\"'image'\"\n [maxAllowedFiles]=\"1\"\n ></c8y-drop-area>\n <c8y-messages>\n <c8y-message\n name=\"maxFileSizeReached\"\n [text]=\"\n 'The maximum image size is {{ maxFileSize }} kB. The selected image has a size of {{ actualFileSize }} kB.'\n | translate\n \"\n ></c8y-message>\n <c8y-message\n name=\"wrongFileType\"\n [text]=\"'Wrong file type, select an image.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"maxlength\"\n [text]=\"'Only select one image.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"required\"\n [text]=\"'An image is required.' | translate\"\n ></c8y-message>\n <c8y-message\n name=\"minlength\"\n [text]=\"'An image is required.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </fieldset>\n\n <div *ngIf=\"imageSrc$ | async as src\">\n <fieldset class=\"c8y-fieldset\">\n <legend>\n {{ 'Size and alignment' | translate }}\n </legend>\n <div [formGroupName]=\"'styling'\">\n <c8y-form-group class=\"form-group-sm m-b-0\">\n <label class=\"m-b-4\">\n {{ 'Image display' | translate }}\n </label>\n <ul class=\"list-group separator-top-bottom\">\n <li\n class=\"list-group-item d-flex a-i-center p-l-0\"\n *ngFor=\"let objectFitOption of objectFitOptions; let i = index\"\n >\n <label class=\"c8y-radio\">\n <input\n type=\"radio\"\n [id]=\"'groupradiocontentclass' + i\"\n formControlName=\"objectFit\"\n [value]=\"objectFitOption.value\"\n />\n <span></span>\n <span class=\"l-h-1\">\n {{ objectFitOption.label | translate }}\n <br />\n <small class=\"text-muted\">\n {{ objectFitOption.description | translate }}\n </small>\n </span>\n </label>\n </li>\n </ul>\n </c8y-form-group>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <c8y-form-group class=\"form-group-sm\">\n <label>{{ 'Horizontal alignment' | translate }}</label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n formControlName=\"objectPositionX\"\n >\n <option [ngValue]=\"'left'\">\n {{ 'left`horizontal alignment`' | translate }}\n </option>\n <option [ngValue]=\"'center'\">\n {{ 'center`horizontal alignment`' | translate }}\n </option>\n <option [ngValue]=\"'right'\">\n {{ 'right`horizontal alignment`' | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n </div>\n <div class=\"col-md-6\">\n <c8y-form-group class=\"form-group-sm\">\n <label>{{ 'Vertical alignment' | translate }}</label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n formControlName=\"objectPositionY\"\n >\n <option [ngValue]=\"'top'\">\n {{ 'top`vertical alignment`' | translate }}\n </option>\n <option [ngValue]=\"'center'\">\n {{ 'center`vertical alignment`' | translate }}\n </option>\n <option [ngValue]=\"'bottom'\">\n {{ 'bottom`vertical alignment`' | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n </div>\n </div>\n </div>\n </fieldset>\n <ng-template #imagePreview>\n <img\n [ngStyle]=\"styling\"\n [src]=\"src\"\n [ngClass]=\"styling ? 'fit-h fit-w' : 'img-responsive'\"\n />\n </ng-template>\n </div>\n <div\n class=\"d-flex j-c-center\"\n *ngIf=\"loading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: i1$1.NgForm }, { type: i2.FilesService }, { type: i2.AlertService }, { type: ImageWidgetService }, { type: i4.WidgetConfigComponent, decorators: [{
type: Optional
}] }, { type: i4.WidgetConfigService }], propDecorators: { config: [{
type: Input
}], imagePreviewTemplate: [{
type: ViewChildren,
args: ['imagePreview']
}] } });
class ImageWidgetViewComponent {
constructor(imageWidget) {
this.imageWidget = imageWidget;
this.imageBinaryId$ = new BehaviorSubject(null);
this.loading = true;
this.imageDetails$ = this.imageBinaryId$.pipe(distinctUntilChanged(), tap(() => (this.loading = true)), switchMap(imageBinaryId => this.imageWidget.getImageDetails(imageBinaryId)), tap(() => (this.loading = false)), shareReplay(1));
}
ngOnChanges(changes) {
if (changes.config) {
const value = changes.config.currentValue;
this.imageBinaryId$.next(value.imageBinaryId);
this.setStyling(value);
}
}
setStyling(config) {
this.styling = this.imageWidget.getStyling(config);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ImageWidgetViewComponent, deps: [{ token: ImageWidgetService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ImageWidgetViewComponent, isStandalone: true, selector: "c8y-image-widget-view", inputs: { config: "config" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"imageDetails$ | async as details; else empty\">\n <img\n [src]=\"details.base64\"\n [title]=\"details.file.name\"\n [ngClass]=\"styling ? 'fit-h fit-w' : 'img-responsive'\"\n [ngStyle]=\"styling\"\n />\n</ng-container>\n\n<ng-template #empty>\n <div class=\"d-flex fit-h fit-w j-c-center a-i-center\" *ngIf=\"!loading\">\n <c8y-ui-empty-state\n class=\"fit-w\"\n [icon]=\"'no-image'\"\n [title]=\"'No image to display.' | translate\"\n [subtitle]=\"'Upload an image.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n</ng-template>\n<div class=\"d-flex fit-h fit-w j-c-center a-i-center\" *ngIf=\"loading\">\n <c8y-loading></c8y-loading>\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ImageWidgetViewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-image-widget-view', standalone: true, imports: [NgIf, NgClass, AsyncPipe, NgStyle, LoadingComponent, EmptyStateComponent], template: "<ng-container *ngIf=\"imageDetails$ | async as details; else empty\">\n <img\n [src]=\"details.base64\"\n [title]=\"details.file.name\"\n [ngClass]=\"styling ? 'fit-h fit-w' : 'img-responsive'\"\n [ngStyle]=\"styling\"\n />\n</ng-container>\n\n<ng-template #empty>\n <div class=\"d-flex fit-h fit-w j-c-center a-i-center\" *ngIf=\"!loading\">\n <c8y-ui-empty-state\n class=\"fit-w\"\n [icon]=\"'no-image'\"\n [title]=\"'No image to display.' | translate\"\n [subtitle]=\"'Upload an image.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n</ng-template>\n<div class=\"d-flex fit-h fit-w j-c-center a-i-center\" *ngIf=\"loading\">\n <c8y-loading></c8y-loading>\n</div>\n" }]
}], ctorParameters: () => [{ type: ImageWidgetService }], propDecorators: { config: [{
type: Input
}] } });
/**
* Generated bundle index. Do not edit.
*/
export { ImageWidgetConfigComponent, ImageWidgetService, ImageWidgetViewComponent, defaultObjectFitValue, defaultObjectPositionValue };
//# sourceMappingURL=c8y-ngx-components-widgets-implementations-image.mjs.map