@c8y/ngx-components 1023.43.3 → 1023.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/agent-chat/index.d.ts +6 -1
- package/ai/agent-chat/index.d.ts.map +1 -1
- package/ai/ai-chat/index.d.ts.map +1 -1
- package/ai/index.d.ts +39 -30
- package/ai/index.d.ts.map +1 -1
- package/datapoints-export-selector/index.d.ts +2 -1
- package/datapoints-export-selector/index.d.ts.map +1 -1
- package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs +24 -9
- package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs +5 -4
- package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ai.mjs +63 -33
- package/fesm2022/c8y-ngx-components-ai.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer.mjs +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +6 -3
- package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-echart.mjs +17 -11
- package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-global-context.mjs +29 -20
- package/fesm2022/c8y-ngx-components-global-context.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-search.mjs +4 -1
- package/fesm2022/c8y-ngx-components-search.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-trusted-certificates.mjs +1 -5
- package/fesm2022/c8y-ngx-components-trusted-certificates.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-upgrade.mjs +3 -33
- package/fesm2022/c8y-ngx-components-upgrade.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs +1203 -34
- package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-markdown.mjs +3 -2
- package/fesm2022/c8y-ngx-components-widgets-definitions-markdown.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +32 -4
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs +14 -6
- package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-kpi.mjs +10 -5
- package/fesm2022/c8y-ngx-components-widgets-implementations-kpi.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-markdown.mjs +122 -80
- package/fesm2022/c8y-ngx-components-widgets-implementations-markdown.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +66 -7
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/global-context/index.d.ts.map +1 -1
- package/index.d.ts +31 -3
- package/index.d.ts.map +1 -1
- package/locales/de.po +14 -20
- package/locales/es.po +13 -19
- package/locales/fr.po +18 -24
- package/locales/ja_JP.po +13 -19
- package/locales/ko.po +13 -19
- package/locales/locales.pot +88 -17
- package/locales/nl.po +13 -19
- package/locales/pl.po +13 -19
- package/locales/pt_BR.po +13 -19
- package/locales/zh_CN.po +13 -19
- package/locales/zh_TW.po +13 -19
- package/package.json +1 -1
- package/search/index.d.ts.map +1 -1
- package/trusted-certificates/index.d.ts +0 -2
- package/trusted-certificates/index.d.ts.map +1 -1
- package/upgrade/index.d.ts.map +1 -1
- package/widgets/definitions/markdown/index.d.ts +1 -1
- package/widgets/implementations/datapoints-graph/index.d.ts +3 -0
- package/widgets/implementations/datapoints-graph/index.d.ts.map +1 -1
- package/widgets/implementations/html-widget/index.d.ts +4 -1
- package/widgets/implementations/html-widget/index.d.ts.map +1 -1
- package/widgets/implementations/kpi/index.d.ts.map +1 -1
- package/widgets/implementations/markdown/index.d.ts +23 -13
- package/widgets/implementations/markdown/index.d.ts.map +1 -1
- package/fesm2022/c8y-ngx-components-upgrade-not-found.component-CuCuYAkK.mjs +0 -19
- package/fesm2022/c8y-ngx-components-upgrade-not-found.component-CuCuYAkK.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"c8y-ngx-components-widgets-implementations-kpi.mjs","sources":["../../widgets/implementations/kpi/kpi-widget-view/kpi-widget-view.component.ts","../../widgets/implementations/kpi/kpi-widget-view/kpi-widget-view.component.html","../../widgets/implementations/kpi/kpi-widget-config/kpi-widget-config.component.ts","../../widgets/implementations/kpi/kpi-widget-config/kpi-widget-config.component.html","../../widgets/implementations/kpi/c8y-ngx-components-widgets-implementations-kpi.ts"],"sourcesContent":["import { Component, Input, OnInit, Optional } from '@angular/core';\nimport { CoreModule, MeasurementRealtimeService } from '@c8y/ngx-components';\nimport { KPIDetails } from '@c8y/ngx-components/datapoint-selector';\nimport { combineLatest, NEVER, Observable } from 'rxjs';\nimport { distinctUntilChanged, filter, map, pairwise, startWith, tap } from 'rxjs/operators';\nimport { ContextDashboardComponent } from '@c8y/ngx-components/context-dashboard';\nimport { KpiWidgetConfig } from '../kpi-widget.model';\n\ninterface MeasurementValue {\n unit?: string;\n value: number;\n date: string;\n}\n\nenum ColorClass {\n danger = 'text-danger',\n warning = 'text-warning',\n unknown = ''\n}\n\n@Component({\n selector: 'c8y-kpi-widget-view',\n templateUrl: './kpi-widget-view.component.html',\n standalone: true,\n imports: [CoreModule],\n providers: [MeasurementRealtimeService]\n})\nexport class KpiWidgetViewComponent implements OnInit {\n @Input() config: KpiWidgetConfig = { datapoints: [] };\n state$: Observable<{\n latestMeasurement: MeasurementValue;\n previousValue: MeasurementValue | undefined;\n trend: string;\n unit: string;\n colorClass: ColorClass;\n }> = NEVER;\n\n // used to differentiate between loading state and empty state\n noDataInitiallyInDB = false;\n\n constructor(\n private measurementRealtime: MeasurementRealtimeService,\n @Optional() private dashboard: ContextDashboardComponent\n ) {}\n\n async ngOnInit() {\n const datapoints = this.config.datapoints || [];\n const datapoint: KPIDetails = datapoints.find(tmp => tmp?.__active);\n if (!datapoint) {\n return;\n }\n\n this.state$ = this.setupObservable(datapoint);\n }\n\n setupObservable(datapoint: KPIDetails): Observable<{\n latestMeasurement: MeasurementValue;\n previousValue: MeasurementValue | undefined;\n trend: string;\n unit: string;\n colorClass: ColorClass;\n }> {\n this.assignContextFromContextDashboard(datapoint);\n const latestMeasurement$ = this.getLatestMeasurement$(datapoint);\n const lastTwoValues$ = this.getLastTwoValuesOfObservable$(latestMeasurement$);\n\n const previousValue$ = lastTwoValues$.pipe(\n map(([previousVal]) => previousVal),\n startWith(undefined as MeasurementValue | undefined)\n );\n\n const unit$ = latestMeasurement$.pipe(\n map(latestMeasurementValue => datapoint.unit || latestMeasurementValue.unit || ''),\n startWith(''),\n distinctUntilChanged()\n );\n\n return combineLatest([\n latestMeasurement$,\n previousValue$,\n this.getTrendOfLatestMeasurements$(lastTwoValues$),\n unit$,\n this.getColorClass$(latestMeasurement$, datapoint)\n ]).pipe(\n map(([latestMeasurement, previousValue, trend, unit, colorClass]) => {\n return {\n latestMeasurement,\n previousValue,\n trend,\n unit,\n colorClass\n };\n })\n );\n }\n\n private getLatestMeasurement$(datapoint: KPIDetails): Observable<MeasurementValue> {\n return this.measurementRealtime\n .latestValueOfSpecificMeasurement$(\n datapoint.fragment,\n datapoint.series,\n datapoint.__target,\n // we only need the last two values in case we want to show a trend\n this.config.showTrend ? 2 : 1,\n // null will be emitted in case no measurement was found initially\n true\n )\n .pipe(\n tap(measurement => {\n if (!measurement) {\n this.noDataInitiallyInDB = true;\n }\n }),\n filter(measurement => !!measurement),\n map(measurement => {\n return {\n unit: measurement[datapoint.fragment][datapoint.series].unit,\n value: measurement[datapoint.fragment][datapoint.series].value,\n date: measurement.time as string\n };\n })\n );\n }\n\n private getColorClass$(\n measurementAndDatapointCombination$: Observable<MeasurementValue>,\n datapoint: KPIDetails\n ): Observable<ColorClass> {\n return measurementAndDatapointCombination$.pipe(\n map(latestMeasurementValue => {\n if (this.inRangeOf(datapoint, latestMeasurementValue.value, 'redRangeMin', 'redRangeMax')) {\n return ColorClass.danger;\n }\n\n if (\n this.inRangeOf(\n datapoint,\n latestMeasurementValue.value,\n 'yellowRangeMin',\n 'yellowRangeMax'\n )\n ) {\n return ColorClass.warning;\n }\n\n return ColorClass.unknown;\n }),\n startWith(ColorClass.unknown),\n distinctUntilChanged()\n );\n }\n\n private getLastTwoValuesOfObservable$<T>(input$: Observable<T>): Observable<T[]> {\n return input$.pipe(pairwise());\n }\n\n private getTrendOfLatestMeasurements$(latestMeasurement$: Observable<MeasurementValue[]>) {\n return latestMeasurement$.pipe(\n map(res => {\n if (res.length === 2) {\n const oldValue = res[0].value;\n const newValue = res[1].value;\n if (oldValue < newValue) {\n return '45deg';\n }\n if (oldValue > newValue) {\n return '135deg';\n }\n }\n return '90deg';\n }),\n startWith('90deg'),\n distinctUntilChanged()\n );\n }\n\n private inRangeOf(\n datapoint: KPIDetails,\n measurementValue: number,\n minAttribute: string,\n maxAttribute: string\n ): boolean {\n if (\n typeof datapoint[minAttribute] === 'number' &&\n typeof datapoint[maxAttribute] === 'number'\n ) {\n if (\n measurementValue >= datapoint[minAttribute] &&\n measurementValue < datapoint[maxAttribute]\n ) {\n return true;\n }\n }\n return false;\n }\n\n private assignContextFromContextDashboard(datapoint: KPIDetails) {\n if (!this.dashboard?.isDeviceTypeDashboard) {\n return;\n }\n const context = this.dashboard?.context;\n if (context?.id) {\n const { name, id } = context;\n datapoint.__target = { name, id };\n }\n }\n}\n","<div\n class=\"kpi-widget__container d-flex d-col fit-h fit-w a-i-center j-c-center\"\n *ngIf=\"state$ | async as lastState; else noMeasurementFound\"\n>\n <div class=\"d-flex a-i-center j-c-center fit-w\">\n <div\n class=\"m-r-16 flex-no-shrink text-muted\"\n [ngClass]=\"lastState.colorClass\"\n *ngIf=\"config.icon && config.showIcon\"\n >\n <i class=\"icon-32\" [c8yIcon]=\"config.icon\"></i>\n </div>\n <div class=\"text-truncate\">\n <span\n class=\"text-truncate text-medium\"\n [ngClass]=\"lastState.colorClass\"\n [ngStyle]=\"{ 'font-size': (config.fontSize || '36') + 'px' }\"\n title=\"{{\n lastState.colorClass === 'text-danger'\n ? ('Within red range:' | translate)\n : lastState.colorClass === 'text-warning'\n ? ('Within yellow range:' | translate)\n : ''\n }} {{\n lastState.latestMeasurement.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')\n }} {{ lastState.unit || '' }}\"\n >\n {{\n lastState.latestMeasurement.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')\n }}\n <small class=\"text-regular\">{{ lastState.unit || '' }}</small>\n </span>\n </div>\n <div\n class=\"dot dot-info dot-30 m-l-16 flex-no-shrink\"\n *ngIf=\"config?.showTrend && lastState.previousValue as previousValue\"\n >\n <i\n class=\"icon-20\"\n [title]=\"\n ('Previous value' | translate) +\n ': ' +\n (previousValue.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')) +\n ' (' +\n (previousValue.date | date: 'medium') +\n ')'\n \"\n c8yIcon=\"arrow-dotted-up\"\n [ngStyle]=\"{ transform: 'rotate(' + lastState.trend + ')' }\"\n ></i>\n </div>\n </div>\n <div class=\"d-flex j-c-center\">\n <p *ngIf=\"config?.showTimestamp\" class=\"icon-flex text-center text-muted small\">\n <i c8yIcon=\"calendar\"></i>\n {{ lastState.latestMeasurement.date | date: 'medium' }}\n </p>\n </div>\n</div>\n\n<ng-template #noMeasurementFound>\n <div class=\"d-flex fit-h fit-w j-c-center a-i-center\">\n <c8y-ui-empty-state\n *ngIf=\"noDataInitiallyInDB\"\n class=\"fit-w\"\n [icon]=\"'line-chart'\"\n [title]=\"'No measurement to display.' | translate\"\n [subtitle]=\"'Waiting for measurements to be created.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <c8y-loading *ngIf=\"!noDataInitiallyInDB\"></c8y-loading>\n </div>\n</ng-template>\n","import { Component, Input, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';\nimport {\n AbstractControl,\n ControlContainer,\n FormBuilder,\n NgForm,\n ValidationErrors,\n ValidatorFn,\n Validators\n} from '@angular/forms';\nimport { CoreModule, OnBeforeSave } from '@c8y/ngx-components';\nimport { WidgetConfigComponent, WidgetConfigService } from '@c8y/ngx-components/context-dashboard';\nimport {\n DatapointAttributesFormConfig,\n DatapointSelectorModalOptions,\n DatapointSelectorModule,\n KPIDetails\n} from '@c8y/ngx-components/datapoint-selector';\nimport { Observable, Subject } from 'rxjs';\nimport { debounceTime, takeUntil } from 'rxjs/operators';\nimport { KpiWidgetConfig } from '../kpi-widget.model';\nimport { IconSelectorModule } from '@c8y/ngx-components/icon-selector';\nimport { PopoverModule } from 'ngx-bootstrap/popover';\nimport { KpiWidgetViewComponent } from '../kpi-widget-view/kpi-widget-view.component';\n\nexport function exactlyASingleDatapointActive(): ValidatorFn {\n return (control: AbstractControl): ValidationErrors | null => {\n const datapoints: KPIDetails[] = control.value;\n\n if (!datapoints || !datapoints.length) {\n return null;\n }\n\n const activeDatapoints = datapoints.filter(datapoint => datapoint.__active);\n\n if (activeDatapoints.length === 1) {\n return null;\n }\n\n return { exactlyOneDatapointNeedsToBeActive: true };\n };\n}\n\n@Component({\n selector: 'c8y-kpi-widget-config',\n templateUrl: './kpi-widget-config.component.html',\n standalone: true,\n imports: [\n CoreModule,\n DatapointSelectorModule,\n IconSelectorModule,\n PopoverModule,\n KpiWidgetViewComponent\n ],\n viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]\n})\nexport class KpiWidgetConfigComponent implements OnInit, OnDestroy, OnBeforeSave {\n @ViewChild('kpiPreview')\n set previewMapSet(template: TemplateRef<unknown>) {\n if (template) {\n this.widgetConfigService.setPreview(template);\n return;\n }\n this.widgetConfigService.setPreview(null);\n }\n\n @Input() config: KpiWidgetConfig;\n previewActiveDatapoint: KPIDetails;\n datapointSelectionConfig: Partial<DatapointSelectorModalOptions> = {};\n defaultFormOptions: Partial<DatapointAttributesFormConfig> = {\n showRedRange: true,\n showYellowRange: true\n };\n formGroup: ReturnType<KpiWidgetConfigComponent['createForm']>;\n availableIcons: string[] = [];\n previewConfig: KpiWidgetConfig;\n private destroy$ = new Subject<void>();\n private limits = {\n fontSizeMax: 72,\n fontSizeMin: 18,\n numberOfDecimalPlacesMax: 10,\n numberOfDecimalPlacesMin: 0\n } as const;\n\n constructor(\n private formBuilder: FormBuilder,\n private form: NgForm,\n private widgetConfig: WidgetConfigComponent,\n private widgetConfigService: WidgetConfigService\n ) {}\n\n onBeforeSave(config?: KpiWidgetConfig): boolean | Promise<boolean> | Observable<boolean> {\n if (this.formGroup.valid) {\n Object.assign(config, this.formGroup.value);\n return true;\n }\n return false;\n }\n\n async ngOnInit() {\n if (this.widgetConfig.context?.id) {\n this.datapointSelectionConfig.contextAsset = this.widgetConfig?.context;\n }\n\n this.previewConfig = { ...this.config };\n\n this.initForm();\n if (this.config?.datapoints) {\n this.formGroup.patchValue({ datapoints: this.config.datapoints });\n\n if (this.config.datapoints.length > 0) {\n this.previewActiveDatapoint = this.config.datapoints.find(dp => dp.__active);\n }\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n private applyLimits(value: number, min: number, max: number): number {\n if (value < min) {\n return min;\n }\n if (value > max) {\n return max;\n }\n return value;\n }\n\n private initForm(): void {\n this.formGroup = this.createForm();\n this.form.form.addControl('config', this.formGroup);\n this.formGroup.patchValue(this.config);\n\n this.formGroup.valueChanges\n .pipe(debounceTime(100), takeUntil(this.destroy$))\n .subscribe(formValue => {\n if (formValue.datapoints) {\n this.previewActiveDatapoint = formValue.datapoints.find(dp => dp.__active);\n }\n\n const previewLimitedValue = this.createPreviewLimitedValue(formValue);\n\n this.previewConfig = { ...this.config, ...previewLimitedValue };\n\n Object.assign(this.config, formValue);\n });\n }\n\n private createPreviewLimitedValue(formValue: Partial<KpiWidgetConfig>): Partial<KpiWidgetConfig> {\n const previewValue = { ...formValue };\n\n if (previewValue.numberOfDecimalPlaces !== undefined) {\n previewValue.numberOfDecimalPlaces = this.applyLimits(\n previewValue.numberOfDecimalPlaces,\n this.limits.numberOfDecimalPlacesMin,\n this.limits.numberOfDecimalPlacesMax\n );\n }\n\n if (previewValue.fontSize !== undefined) {\n previewValue.fontSize = this.applyLimits(\n previewValue.fontSize,\n this.limits.fontSizeMin,\n this.limits.fontSizeMax\n );\n }\n\n return previewValue;\n }\n\n private createForm() {\n return this.formBuilder.group({\n numberOfDecimalPlaces: [\n 2,\n [\n Validators.required,\n Validators.min(this.limits.numberOfDecimalPlacesMin),\n Validators.max(this.limits.numberOfDecimalPlacesMax)\n ]\n ],\n showTimestamp: [true, []],\n showTrend: [true, []],\n showIcon: [true, []],\n icon: ['water', [Validators.required, Validators.minLength(1)]],\n fontSize: [\n 36,\n [\n Validators.required,\n Validators.min(this.limits.fontSizeMin),\n Validators.max(this.limits.fontSizeMax)\n ]\n ],\n datapoints: this.formBuilder.control(new Array<KPIDetails>(), [\n Validators.required,\n Validators.minLength(1),\n exactlyASingleDatapointActive()\n ])\n });\n }\n}\n","<form [formGroup]=\"formGroup\">\n <c8y-datapoint-selection-list\n class=\"bg-inherit no-card-context\"\n name=\"datapoints\"\n [defaultFormOptions]=\"defaultFormOptions\"\n [config]=\"datapointSelectionConfig\"\n [minActiveCount]=\"1\"\n [maxActiveCount]=\"1\"\n formControlName=\"datapoints\"\n ></c8y-datapoint-selection-list>\n\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Layout' | translate }}</legend>\n <div class=\"row tight-grid\">\n <div class=\"col-md-3\">\n <div class=\"form-group form-group-sm d-flex a-i-center gap-8 m-b-0 m-t-8\">\n <label translate>Icon</label>\n <c8y-icon-selector-wrapper\n name=\"icon\"\n formControlName=\"icon\"\n ></c8y-icon-selector-wrapper>\n </div>\n </div>\n <div class=\"col-md-9\">\n <c8y-form-group class=\"form-group-sm m-b-16\">\n <label\n [title]=\"'Font size of measurement value (px)' | translate\"\n translate\n >\n Font size of measurement value (px)\n </label>\n <input\n class=\"form-control\"\n name=\"fontSize\"\n type=\"number\"\n formControlName=\"fontSize\"\n [placeholder]=\"'e.g. {{ example }}' | translate: { example: 36 }\"\n />\n <c8y-messages\n [show]=\"formGroup.controls?.fontSize?.touched && formGroup?.controls?.fontSize?.errors\"\n ></c8y-messages>\n </c8y-form-group>\n </div>\n </div>\n </fieldset>\n\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Display' | translate }}</legend>\n <div class=\"d-flex gap-16 flex-wrap\">\n <c8y-form-group class=\"m-b-8\">\n <label\n class=\"c8y-checkbox\"\n [title]=\"'Show timestamp' | translate\"\n >\n <input\n name=\"showTimestamp\"\n type=\"checkbox\"\n formControlName=\"showTimestamp\"\n />\n <span></span>\n <span translate>Show timestamp</span>\n </label>\n </c8y-form-group>\n\n <c8y-form-group class=\"m-b-8\">\n <label\n class=\"c8y-checkbox\"\n [title]=\"'Show icon' | translate\"\n >\n <input\n name=\"showIcon\"\n type=\"checkbox\"\n formControlName=\"showIcon\"\n />\n <span></span>\n <span translate>Show icon</span>\n </label>\n </c8y-form-group>\n\n <c8y-form-group class=\"m-b-8\">\n <label\n class=\"c8y-checkbox\"\n [title]=\"'Show trend icon' | translate\"\n >\n <input\n name=\"showTrend\"\n type=\"checkbox\"\n formControlName=\"showTrend\"\n />\n <span></span>\n <span translate>Show trend icon</span>\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'Indicates the trend between the last two measurement values.' | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </label>\n </c8y-form-group>\n </div>\n </fieldset>\n\n <fieldset class=\"c8y-fieldset\">\n <legend translate>Number of decimal places</legend>\n <c8y-form-group class=\"form-group-sm m-b-16\">\n <input\n class=\"form-control\"\n name=\"numberOfDecimalPlaces\"\n type=\"number\"\n formControlName=\"numberOfDecimalPlaces\"\n [placeholder]=\"'e.g. {{ example }}' | translate: { example: 1 }\"\n />\n <c8y-messages\n [show]=\"\n formGroup.controls?.numberOfDecimalPlaces?.touched &&\n formGroup?.controls?.numberOfDecimalPlaces?.errors\n \"\n ></c8y-messages>\n </c8y-form-group>\n </fieldset>\n</form>\n\n<ng-template #kpiPreview>\n @if (formGroup && formGroup.value) {\n @if (formGroup.value.datapoints?.length > 0 && previewActiveDatapoint) {\n <div style=\"height: 300px\">\n @if (previewConfig) {\n <c8y-kpi-widget-view [config]=\"previewConfig\"></c8y-kpi-widget-view>\n }\n </div>\n } @else {\n <div class=\"col-md-6 d-col a-i-start j-c-center\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-data-points'\"\n [title]=\"'No data points selected' | translate\"\n [subtitle]=\"'Select data point to render content' | translate\"\n [horizontal]=\"false\"\n data-cy=\"kpi-widget--empty-state-no-data-point-selected\"\n >\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#kpi\">user documentation</a>.\n </small>\n </p>\n </c8y-ui-empty-state>\n </div>\n }\n }\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1","i3"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"c8y-ngx-components-widgets-implementations-kpi.mjs","sources":["../../widgets/implementations/kpi/kpi-widget-view/kpi-widget-view.component.ts","../../widgets/implementations/kpi/kpi-widget-view/kpi-widget-view.component.html","../../widgets/implementations/kpi/kpi-widget-config/kpi-widget-config.component.ts","../../widgets/implementations/kpi/kpi-widget-config/kpi-widget-config.component.html","../../widgets/implementations/kpi/c8y-ngx-components-widgets-implementations-kpi.ts"],"sourcesContent":["import { Component, Input, OnInit, Optional } from '@angular/core';\nimport { CoreModule, MeasurementRealtimeService } from '@c8y/ngx-components';\nimport { KPIDetails } from '@c8y/ngx-components/datapoint-selector';\nimport { combineLatest, NEVER, Observable } from 'rxjs';\nimport { distinctUntilChanged, filter, map, pairwise, startWith, tap } from 'rxjs/operators';\nimport { ContextDashboardComponent } from '@c8y/ngx-components/context-dashboard';\nimport { KpiWidgetConfig } from '../kpi-widget.model';\n\ninterface MeasurementValue {\n unit?: string;\n value: number;\n date: string;\n}\n\nenum ColorClass {\n danger = 'text-danger',\n warning = 'text-warning',\n unknown = ''\n}\n\n@Component({\n selector: 'c8y-kpi-widget-view',\n templateUrl: './kpi-widget-view.component.html',\n standalone: true,\n imports: [CoreModule],\n providers: [MeasurementRealtimeService]\n})\nexport class KpiWidgetViewComponent implements OnInit {\n @Input() config: KpiWidgetConfig = { datapoints: [] };\n state$: Observable<{\n latestMeasurement: MeasurementValue;\n previousValue: MeasurementValue | undefined;\n trend: string;\n unit: string;\n colorClass: ColorClass;\n }> = NEVER;\n\n // used to differentiate between loading state and empty state\n noDataInitiallyInDB = false;\n\n constructor(\n private measurementRealtime: MeasurementRealtimeService,\n @Optional() private dashboard: ContextDashboardComponent\n ) {}\n\n async ngOnInit() {\n const datapoints = this.config.datapoints || [];\n const datapoint: KPIDetails = datapoints.find(tmp => tmp?.__active);\n if (!datapoint) {\n return;\n }\n\n this.state$ = this.setupObservable(datapoint);\n }\n\n setupObservable(datapoint: KPIDetails): Observable<{\n latestMeasurement: MeasurementValue;\n previousValue: MeasurementValue | undefined;\n trend: string;\n unit: string;\n colorClass: ColorClass;\n }> {\n this.assignContextFromContextDashboard(datapoint);\n const latestMeasurement$ = this.getLatestMeasurement$(datapoint);\n const lastTwoValues$ = this.getLastTwoValuesOfObservable$(latestMeasurement$);\n\n const previousValue$ = lastTwoValues$.pipe(\n map(([previousVal]) => previousVal),\n startWith(undefined as MeasurementValue | undefined)\n );\n\n const unit$ = latestMeasurement$.pipe(\n map(latestMeasurementValue => datapoint.unit || latestMeasurementValue.unit || ''),\n startWith(''),\n distinctUntilChanged()\n );\n\n return combineLatest([\n latestMeasurement$,\n previousValue$,\n this.getTrendOfLatestMeasurements$(lastTwoValues$),\n unit$,\n this.getColorClass$(latestMeasurement$, datapoint)\n ]).pipe(\n map(([latestMeasurement, previousValue, trend, unit, colorClass]) => {\n return {\n latestMeasurement,\n previousValue,\n trend,\n unit,\n colorClass\n };\n })\n );\n }\n\n private getLatestMeasurement$(datapoint: KPIDetails): Observable<MeasurementValue> {\n return this.measurementRealtime\n .latestValueOfSpecificMeasurement$(\n datapoint.fragment,\n datapoint.series,\n datapoint.__target,\n // we only need the last two values in case we want to show a trend\n this.config.showTrend ? 2 : 1,\n // null will be emitted in case no measurement was found initially\n true\n )\n .pipe(\n tap(measurement => {\n if (!measurement) {\n this.noDataInitiallyInDB = true;\n }\n }),\n filter(measurement => !!measurement),\n map(measurement => {\n return {\n unit: measurement[datapoint.fragment][datapoint.series].unit,\n value: measurement[datapoint.fragment][datapoint.series].value,\n date: measurement.time as string\n };\n })\n );\n }\n\n private getColorClass$(\n measurementAndDatapointCombination$: Observable<MeasurementValue>,\n datapoint: KPIDetails\n ): Observable<ColorClass> {\n return measurementAndDatapointCombination$.pipe(\n map(latestMeasurementValue => {\n if (this.inRangeOf(datapoint, latestMeasurementValue.value, 'redRangeMin', 'redRangeMax')) {\n return ColorClass.danger;\n }\n\n if (\n this.inRangeOf(\n datapoint,\n latestMeasurementValue.value,\n 'yellowRangeMin',\n 'yellowRangeMax'\n )\n ) {\n return ColorClass.warning;\n }\n\n return ColorClass.unknown;\n }),\n startWith(ColorClass.unknown),\n distinctUntilChanged()\n );\n }\n\n private getLastTwoValuesOfObservable$<T>(input$: Observable<T>): Observable<T[]> {\n return input$.pipe(pairwise());\n }\n\n private getTrendOfLatestMeasurements$(latestMeasurement$: Observable<MeasurementValue[]>) {\n return latestMeasurement$.pipe(\n map(res => {\n if (res.length === 2) {\n const oldValue = res[0].value;\n const newValue = res[1].value;\n if (oldValue < newValue) {\n return '45deg';\n }\n if (oldValue > newValue) {\n return '135deg';\n }\n }\n return '90deg';\n }),\n startWith('90deg'),\n distinctUntilChanged()\n );\n }\n\n private inRangeOf(\n datapoint: KPIDetails,\n measurementValue: number,\n minAttribute: string,\n maxAttribute: string\n ): boolean {\n if (\n typeof datapoint[minAttribute] === 'number' &&\n typeof datapoint[maxAttribute] === 'number'\n ) {\n if (\n measurementValue >= datapoint[minAttribute] &&\n measurementValue < datapoint[maxAttribute]\n ) {\n return true;\n }\n }\n return false;\n }\n\n private assignContextFromContextDashboard(datapoint: KPIDetails) {\n if (!this.dashboard?.isDeviceTypeDashboard) {\n return;\n }\n const context = this.dashboard?.context;\n if (context?.id) {\n const { name, id } = context;\n datapoint.__target = { name, id };\n }\n }\n}\n","<div\n class=\"kpi-widget__container d-flex d-col fit-h fit-w a-i-center j-c-center\"\n *ngIf=\"state$ | async as lastState; else noMeasurementFound\"\n>\n <div class=\"d-flex a-i-center j-c-center fit-w\">\n <div\n class=\"m-r-16 flex-no-shrink text-muted\"\n [ngClass]=\"lastState.colorClass\"\n *ngIf=\"config.icon && config.showIcon\"\n >\n <i class=\"icon-32\" [c8yIcon]=\"config.icon\"></i>\n </div>\n <div class=\"text-truncate\">\n <span\n class=\"text-truncate text-medium\"\n [ngClass]=\"lastState.colorClass\"\n [ngStyle]=\"{ 'font-size': (config.fontSize || '36') + 'px' }\"\n title=\"{{\n lastState.colorClass === 'text-danger'\n ? ('Within red range:' | translate)\n : lastState.colorClass === 'text-warning'\n ? ('Within yellow range:' | translate)\n : ''\n }} {{\n lastState.latestMeasurement.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')\n }} {{ lastState.unit || '' }}\"\n >\n {{\n lastState.latestMeasurement.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')\n }}\n <small class=\"text-regular\">{{ lastState.unit || '' }}</small>\n </span>\n </div>\n <div\n class=\"dot dot-info dot-30 m-l-16 flex-no-shrink\"\n *ngIf=\"config?.showTrend && lastState.previousValue as previousValue\"\n >\n <i\n class=\"icon-20\"\n [title]=\"\n ('Previous value' | translate) +\n ': ' +\n (previousValue.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')) +\n ' (' +\n (previousValue.date | date: 'medium') +\n ')'\n \"\n c8yIcon=\"arrow-dotted-up\"\n [ngStyle]=\"{ transform: 'rotate(' + lastState.trend + ')' }\"\n ></i>\n </div>\n </div>\n <div class=\"d-flex j-c-center\">\n <p *ngIf=\"config?.showTimestamp\" class=\"icon-flex text-center text-muted small\">\n <i c8yIcon=\"calendar\"></i>\n {{ lastState.latestMeasurement.date | date: 'medium' }}\n </p>\n </div>\n</div>\n\n<ng-template #noMeasurementFound>\n <div class=\"d-flex fit-h fit-w j-c-center a-i-center\">\n <c8y-ui-empty-state\n *ngIf=\"noDataInitiallyInDB\"\n class=\"fit-w\"\n [icon]=\"'line-chart'\"\n [title]=\"'No measurement to display.' | translate\"\n [subtitle]=\"'Waiting for measurements to be created.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <c8y-loading *ngIf=\"!noDataInitiallyInDB\"></c8y-loading>\n </div>\n</ng-template>\n","import { Component, Input, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';\nimport {\n AbstractControl,\n ControlContainer,\n FormBuilder,\n NgForm,\n ValidationErrors,\n ValidatorFn,\n Validators\n} from '@angular/forms';\nimport { C8yValidators, CoreModule, OnBeforeSave } from '@c8y/ngx-components';\nimport { WidgetConfigComponent, WidgetConfigService } from '@c8y/ngx-components/context-dashboard';\nimport {\n DatapointAttributesFormConfig,\n DatapointSelectorModalOptions,\n DatapointSelectorModule,\n KPIDetails\n} from '@c8y/ngx-components/datapoint-selector';\nimport { Observable, Subject } from 'rxjs';\nimport { debounceTime, takeUntil } from 'rxjs/operators';\nimport { KpiWidgetConfig } from '../kpi-widget.model';\nimport { IconSelectorModule } from '@c8y/ngx-components/icon-selector';\nimport { PopoverModule } from 'ngx-bootstrap/popover';\nimport { KpiWidgetViewComponent } from '../kpi-widget-view/kpi-widget-view.component';\n\nexport function exactlyASingleDatapointActive(): ValidatorFn {\n return (control: AbstractControl): ValidationErrors | null => {\n const datapoints: KPIDetails[] = control.value;\n\n if (!datapoints || !datapoints.length) {\n return null;\n }\n\n const activeDatapoints = datapoints.filter(datapoint => datapoint.__active);\n\n if (activeDatapoints.length === 1) {\n return null;\n }\n\n return { exactlyOneDatapointNeedsToBeActive: true };\n };\n}\n\n@Component({\n selector: 'c8y-kpi-widget-config',\n templateUrl: './kpi-widget-config.component.html',\n standalone: true,\n imports: [\n CoreModule,\n DatapointSelectorModule,\n IconSelectorModule,\n PopoverModule,\n KpiWidgetViewComponent\n ],\n viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]\n})\nexport class KpiWidgetConfigComponent implements OnInit, OnDestroy, OnBeforeSave {\n @ViewChild('kpiPreview')\n set previewMapSet(template: TemplateRef<unknown>) {\n if (template) {\n this.widgetConfigService.setPreview(template);\n return;\n }\n this.widgetConfigService.setPreview(null);\n }\n\n @Input() config: KpiWidgetConfig;\n previewActiveDatapoint: KPIDetails;\n datapointSelectionConfig: Partial<DatapointSelectorModalOptions> = {};\n defaultFormOptions: Partial<DatapointAttributesFormConfig> = {\n showRedRange: true,\n showYellowRange: true\n };\n formGroup: ReturnType<KpiWidgetConfigComponent['createForm']>;\n availableIcons: string[] = [];\n previewConfig: KpiWidgetConfig;\n private destroy$ = new Subject<void>();\n private limits = {\n fontSizeMax: 72,\n fontSizeMin: 18,\n numberOfDecimalPlacesMax: 10,\n numberOfDecimalPlacesMin: 0\n } as const;\n\n constructor(\n private formBuilder: FormBuilder,\n private form: NgForm,\n private widgetConfig: WidgetConfigComponent,\n private widgetConfigService: WidgetConfigService\n ) {}\n\n onBeforeSave(config?: KpiWidgetConfig): boolean | Promise<boolean> | Observable<boolean> {\n if (this.formGroup.valid) {\n Object.assign(config, this.formGroup.value);\n return true;\n }\n return false;\n }\n\n async ngOnInit() {\n if (this.widgetConfig.context?.id) {\n this.datapointSelectionConfig.contextAsset = this.widgetConfig?.context;\n }\n\n this.previewConfig = { ...this.config };\n\n this.initForm();\n if (this.config?.datapoints) {\n this.formGroup.patchValue({ datapoints: this.config.datapoints });\n\n if (this.config.datapoints.length > 0) {\n this.previewActiveDatapoint = this.config.datapoints.find(dp => dp.__active);\n }\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n private applyLimits(value: number, min: number, max: number): number {\n if (value < min) {\n return min;\n }\n if (value > max) {\n return max;\n }\n return value;\n }\n\n private initForm(): void {\n this.formGroup = this.createForm();\n this.form.form.addControl('config', this.formGroup);\n this.formGroup.patchValue(this.config);\n\n this.formGroup.valueChanges\n .pipe(debounceTime(100), takeUntil(this.destroy$))\n .subscribe(formValue => {\n if (formValue.datapoints) {\n this.previewActiveDatapoint = formValue.datapoints.find(dp => dp.__active);\n }\n\n const previewLimitedValue = this.createPreviewLimitedValue(formValue);\n\n if (this.formGroup.valid) {\n // don't apply invalid values to preview to avoid errors\n // e.g. invalid value of numberOfDecimalPlaces provided to number pipe\n this.previewConfig = { ...this.config, ...previewLimitedValue };\n }\n\n Object.assign(this.config, formValue);\n });\n }\n\n private createPreviewLimitedValue(formValue: Partial<KpiWidgetConfig>): Partial<KpiWidgetConfig> {\n const previewValue = { ...formValue };\n\n if (previewValue.numberOfDecimalPlaces !== undefined) {\n previewValue.numberOfDecimalPlaces = this.applyLimits(\n previewValue.numberOfDecimalPlaces,\n this.limits.numberOfDecimalPlacesMin,\n this.limits.numberOfDecimalPlacesMax\n );\n }\n\n if (previewValue.fontSize !== undefined) {\n previewValue.fontSize = this.applyLimits(\n previewValue.fontSize,\n this.limits.fontSizeMin,\n this.limits.fontSizeMax\n );\n }\n\n return previewValue;\n }\n\n private createForm() {\n return this.formBuilder.group({\n numberOfDecimalPlaces: [\n 2,\n [\n Validators.required,\n Validators.min(this.limits.numberOfDecimalPlacesMin),\n Validators.max(this.limits.numberOfDecimalPlacesMax),\n C8yValidators.integerValidator()\n ]\n ],\n showTimestamp: [true, []],\n showTrend: [true, []],\n showIcon: [true, []],\n icon: ['water', [Validators.required, Validators.minLength(1)]],\n fontSize: [\n 36,\n [\n Validators.required,\n Validators.min(this.limits.fontSizeMin),\n Validators.max(this.limits.fontSizeMax)\n ]\n ],\n datapoints: this.formBuilder.control(new Array<KPIDetails>(), [\n Validators.required,\n Validators.minLength(1),\n exactlyASingleDatapointActive()\n ])\n });\n }\n}\n","<form [formGroup]=\"formGroup\">\n <c8y-datapoint-selection-list\n class=\"bg-inherit no-card-context\"\n name=\"datapoints\"\n [defaultFormOptions]=\"defaultFormOptions\"\n [config]=\"datapointSelectionConfig\"\n [minActiveCount]=\"1\"\n [maxActiveCount]=\"1\"\n formControlName=\"datapoints\"\n ></c8y-datapoint-selection-list>\n\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Layout' | translate }}</legend>\n <div class=\"row tight-grid\">\n <div class=\"col-md-3\">\n <div class=\"form-group form-group-sm d-flex a-i-center gap-8 m-b-0 m-t-8\">\n <label translate>Icon</label>\n <c8y-icon-selector-wrapper\n name=\"icon\"\n formControlName=\"icon\"\n ></c8y-icon-selector-wrapper>\n </div>\n </div>\n <div class=\"col-md-9\">\n <c8y-form-group class=\"form-group-sm m-b-16\">\n <label\n [title]=\"'Font size of measurement value (px)' | translate\"\n translate\n >\n Font size of measurement value (px)\n </label>\n <input\n class=\"form-control\"\n name=\"fontSize\"\n type=\"number\"\n formControlName=\"fontSize\"\n [placeholder]=\"'e.g. {{ example }}' | translate: { example: 36 }\"\n />\n <c8y-messages\n [show]=\"formGroup.controls?.fontSize?.touched && formGroup?.controls?.fontSize?.errors\"\n ></c8y-messages>\n </c8y-form-group>\n </div>\n </div>\n </fieldset>\n\n <fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Display' | translate }}</legend>\n <div class=\"d-flex gap-16 flex-wrap\">\n <c8y-form-group class=\"m-b-8\">\n <label\n class=\"c8y-checkbox\"\n [title]=\"'Show timestamp' | translate\"\n >\n <input\n name=\"showTimestamp\"\n type=\"checkbox\"\n formControlName=\"showTimestamp\"\n />\n <span></span>\n <span translate>Show timestamp</span>\n </label>\n </c8y-form-group>\n\n <c8y-form-group class=\"m-b-8\">\n <label\n class=\"c8y-checkbox\"\n [title]=\"'Show icon' | translate\"\n >\n <input\n name=\"showIcon\"\n type=\"checkbox\"\n formControlName=\"showIcon\"\n />\n <span></span>\n <span translate>Show icon</span>\n </label>\n </c8y-form-group>\n\n <c8y-form-group class=\"m-b-8\">\n <label\n class=\"c8y-checkbox\"\n [title]=\"'Show trend icon' | translate\"\n >\n <input\n name=\"showTrend\"\n type=\"checkbox\"\n formControlName=\"showTrend\"\n />\n <span></span>\n <span translate>Show trend icon</span>\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'Indicates the trend between the last two measurement values.' | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </label>\n </c8y-form-group>\n </div>\n </fieldset>\n\n <fieldset class=\"c8y-fieldset\">\n <legend translate>Number of decimal places</legend>\n <c8y-form-group class=\"form-group-sm m-b-20\">\n <input\n class=\"form-control\"\n name=\"numberOfDecimalPlaces\"\n type=\"number\"\n formControlName=\"numberOfDecimalPlaces\"\n [placeholder]=\"'e.g. {{ example }}' | translate: { example: 1 }\"\n />\n <c8y-messages\n [show]=\"\n formGroup.controls?.numberOfDecimalPlaces?.touched &&\n formGroup?.controls?.numberOfDecimalPlaces?.errors\n \"\n ></c8y-messages>\n </c8y-form-group>\n </fieldset>\n</form>\n\n<ng-template #kpiPreview>\n @if (formGroup && formGroup.value) {\n @if (formGroup.value.datapoints?.length > 0 && previewActiveDatapoint) {\n <div style=\"height: 300px\">\n @if (previewConfig) {\n <c8y-kpi-widget-view [config]=\"previewConfig\"></c8y-kpi-widget-view>\n }\n </div>\n } @else {\n <div class=\"col-md-6 d-col a-i-start j-c-center\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-data-points'\"\n [title]=\"'No data points selected' | translate\"\n [subtitle]=\"'Select data point to render content' | translate\"\n [horizontal]=\"false\"\n data-cy=\"kpi-widget--empty-state-no-data-point-selected\"\n >\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#kpi\">user documentation</a>.\n </small>\n </p>\n </c8y-ui-empty-state>\n </div>\n }\n }\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1","i3"],"mappings":"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"}
|
|
@@ -4,13 +4,20 @@ import { gettext } from '@c8y/ngx-components/gettext';
|
|
|
4
4
|
import * as i1 from '@c8y/ngx-components';
|
|
5
5
|
import { C8yValidators, FormGroupComponent, DropAreaComponent, EmptyStateComponent, IconDirective, C8yTranslatePipe, MarkdownToHtmlPipe } from '@c8y/ngx-components';
|
|
6
6
|
import * as i1$1 from '@angular/forms';
|
|
7
|
-
import { Validators, ReactiveFormsModule } from '@angular/forms';
|
|
7
|
+
import { Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
8
8
|
import * as i2 from '@c8y/client';
|
|
9
9
|
import * as i3 from '@ngx-translate/core';
|
|
10
10
|
import { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';
|
|
11
11
|
import { AsyncPipe } from '@angular/common';
|
|
12
|
-
import { Subject } from 'rxjs';
|
|
12
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
13
13
|
import { takeUntil } from 'rxjs/operators';
|
|
14
|
+
import { EditorComponent } from '@c8y/ngx-components/editor';
|
|
15
|
+
|
|
16
|
+
const MarkdownSourceType = {
|
|
17
|
+
WRITE: 'writeMarkdown',
|
|
18
|
+
UPLOAD: 'uploadBinary',
|
|
19
|
+
URL: 'uploadUrl'
|
|
20
|
+
};
|
|
14
21
|
|
|
15
22
|
class MarkdownWidgetService {
|
|
16
23
|
constructor(fileService, inventory, binary, alert, translate, fetchClient, appStateService) {
|
|
@@ -119,19 +126,30 @@ class MarkdownWidgetConfigComponent {
|
|
|
119
126
|
this.form = form;
|
|
120
127
|
this.alert = alert;
|
|
121
128
|
this.markdownService = markdownService;
|
|
122
|
-
this.
|
|
123
|
-
this.
|
|
129
|
+
this.MarkdownSourceType = MarkdownSourceType;
|
|
130
|
+
this.uploadChoice = MarkdownSourceType.URL;
|
|
131
|
+
this.previewMarkdown$ = new BehaviorSubject('');
|
|
132
|
+
this.editorContent = '';
|
|
124
133
|
this.widgetConfigService = inject(WidgetConfigService);
|
|
125
134
|
this.destroy$ = new Subject();
|
|
126
135
|
}
|
|
127
136
|
async onBeforeSave(config) {
|
|
137
|
+
if (this.uploadChoice === MarkdownSourceType.WRITE) {
|
|
138
|
+
Object.assign(config, {
|
|
139
|
+
markdownContent: this.editorContent,
|
|
140
|
+
contentUrl: null,
|
|
141
|
+
markdownBinaryId: null
|
|
142
|
+
});
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
128
145
|
if (this.formGroup.invalid) {
|
|
129
146
|
return false;
|
|
130
147
|
}
|
|
131
|
-
if (this.uploadChoice ===
|
|
148
|
+
if (this.uploadChoice === MarkdownSourceType.URL) {
|
|
132
149
|
Object.assign(config, {
|
|
133
150
|
contentUrl: this.formGroup.value.contentUrl,
|
|
134
|
-
markdownBinaryId: null
|
|
151
|
+
markdownBinaryId: null,
|
|
152
|
+
markdownContent: null
|
|
135
153
|
});
|
|
136
154
|
return true;
|
|
137
155
|
}
|
|
@@ -139,7 +157,7 @@ class MarkdownWidgetConfigComponent {
|
|
|
139
157
|
if (fileFromForm && fileFromForm !== this.fileFromConfig) {
|
|
140
158
|
try {
|
|
141
159
|
const markdownBinaryId = await this.markdownService.uploadFile(fileFromForm);
|
|
142
|
-
Object.assign(config, { markdownBinaryId, contentUrl: null });
|
|
160
|
+
Object.assign(config, { markdownBinaryId, contentUrl: null, markdownContent: null });
|
|
143
161
|
return true;
|
|
144
162
|
}
|
|
145
163
|
catch (e) {
|
|
@@ -148,22 +166,41 @@ class MarkdownWidgetConfigComponent {
|
|
|
148
166
|
}
|
|
149
167
|
}
|
|
150
168
|
if (!fileFromForm) {
|
|
151
|
-
Object.assign(config, {
|
|
169
|
+
Object.assign(config, {
|
|
170
|
+
contentUrl: '/readme.md',
|
|
171
|
+
markdownBinaryId: null,
|
|
172
|
+
markdownContent: null
|
|
173
|
+
});
|
|
152
174
|
}
|
|
153
175
|
return true;
|
|
154
176
|
}
|
|
155
177
|
async ngOnInit() {
|
|
156
|
-
|
|
157
|
-
if (this.config.
|
|
158
|
-
this.uploadChoice =
|
|
159
|
-
this.fileFromConfig = await this.markdownService.getFile(this.config.markdownBinaryId);
|
|
160
|
-
this.formGroup.patchValue({
|
|
161
|
-
droppedFile: [{ file: this.fileFromConfig, name: this.fileFromConfig.name }]
|
|
162
|
-
});
|
|
163
|
-
await this.updatePreviewFromFile(this.fileFromConfig);
|
|
178
|
+
// Determine initial mode from config
|
|
179
|
+
if (this.config.markdownContent) {
|
|
180
|
+
this.uploadChoice = MarkdownSourceType.WRITE;
|
|
164
181
|
}
|
|
165
|
-
else if (this.config.
|
|
166
|
-
this.
|
|
182
|
+
else if (this.config.markdownBinaryId) {
|
|
183
|
+
this.uploadChoice = MarkdownSourceType.UPLOAD;
|
|
184
|
+
}
|
|
185
|
+
this.initForm();
|
|
186
|
+
// Load initial content based on mode
|
|
187
|
+
switch (this.uploadChoice) {
|
|
188
|
+
case MarkdownSourceType.WRITE:
|
|
189
|
+
this.editorContent = this.config.markdownContent;
|
|
190
|
+
this.previewMarkdown$.next(this.config.markdownContent);
|
|
191
|
+
break;
|
|
192
|
+
case MarkdownSourceType.UPLOAD:
|
|
193
|
+
this.fileFromConfig = await this.markdownService.getFile(this.config.markdownBinaryId);
|
|
194
|
+
this.formGroup.patchValue({
|
|
195
|
+
droppedFile: [{ file: this.fileFromConfig, name: this.fileFromConfig.name }]
|
|
196
|
+
});
|
|
197
|
+
await this.updatePreviewFromFile(this.fileFromConfig);
|
|
198
|
+
break;
|
|
199
|
+
case MarkdownSourceType.URL:
|
|
200
|
+
if (this.config.contentUrl) {
|
|
201
|
+
this.previewMarkdown$.next(await this.markdownService.getContentFromUrl(this.config.contentUrl));
|
|
202
|
+
}
|
|
203
|
+
break;
|
|
167
204
|
}
|
|
168
205
|
this.formGroup.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(async (value) => {
|
|
169
206
|
await this.updatePreview(value);
|
|
@@ -177,38 +214,48 @@ class MarkdownWidgetConfigComponent {
|
|
|
177
214
|
this.uploadChoice = value;
|
|
178
215
|
// Ensure dropped file has 'name' property for drop area to display filename
|
|
179
216
|
const droppedFile = this.formGroup.value.droppedFile;
|
|
180
|
-
if (value ===
|
|
217
|
+
if (value === MarkdownSourceType.UPLOAD && droppedFile?.[0]?.file) {
|
|
181
218
|
const normalizedFile = droppedFile.map(item => ({
|
|
182
219
|
...item,
|
|
183
220
|
name: item.name || item.file?.name
|
|
184
221
|
}));
|
|
185
222
|
this.formGroup.controls['droppedFile'].setValue(normalizedFile);
|
|
186
223
|
}
|
|
224
|
+
this.formGroup.updateValueAndValidity();
|
|
225
|
+
}
|
|
226
|
+
onEditorChange(content) {
|
|
227
|
+
this.editorContent = content;
|
|
228
|
+
this.previewMarkdown$.next(content);
|
|
187
229
|
}
|
|
188
230
|
async updatePreview(formValue) {
|
|
189
231
|
const choice = formValue.uploadChoice || this.uploadChoice;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
232
|
+
switch (choice) {
|
|
233
|
+
case MarkdownSourceType.WRITE:
|
|
234
|
+
if (!this.editorContent) {
|
|
235
|
+
this.editorContent = this.previewMarkdown$.getValue();
|
|
236
|
+
}
|
|
237
|
+
this.previewMarkdown$.next(this.editorContent);
|
|
238
|
+
break;
|
|
239
|
+
case MarkdownSourceType.UPLOAD:
|
|
240
|
+
const file = this.getFileFromFormValue(formValue);
|
|
241
|
+
file ? await this.updatePreviewFromFile(file) : this.previewMarkdown$.next('');
|
|
242
|
+
break;
|
|
243
|
+
case MarkdownSourceType.URL:
|
|
244
|
+
if (formValue.contentUrl) {
|
|
245
|
+
this.previewMarkdown$.next(await this.markdownService.getContentFromUrl(formValue.contentUrl));
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
this.previewMarkdown$.next('');
|
|
249
|
+
}
|
|
250
|
+
break;
|
|
204
251
|
}
|
|
205
252
|
}
|
|
206
253
|
async updatePreviewFromFile(file) {
|
|
207
254
|
try {
|
|
208
|
-
this.previewMarkdown
|
|
255
|
+
this.previewMarkdown$.next(await file.text());
|
|
209
256
|
}
|
|
210
257
|
catch {
|
|
211
|
-
this.previewMarkdown
|
|
258
|
+
this.previewMarkdown$.next('');
|
|
212
259
|
}
|
|
213
260
|
}
|
|
214
261
|
getFileFromFormValue(formValue) {
|
|
@@ -223,72 +270,64 @@ class MarkdownWidgetConfigComponent {
|
|
|
223
270
|
Validators.maxLength(1),
|
|
224
271
|
C8yValidators.filesValidator({ maximumFileSizeInKb: 1000 })
|
|
225
272
|
]),
|
|
226
|
-
uploadChoice: this.formBuilder.nonNullable.control(this.
|
|
227
|
-
}, { validators: this.
|
|
273
|
+
uploadChoice: this.formBuilder.nonNullable.control(this.uploadChoice)
|
|
274
|
+
}, { validators: this.requireValidSource() });
|
|
228
275
|
this.form.form.addControl('config', this.formGroup);
|
|
229
276
|
this.formGroup.patchValue(this.config);
|
|
230
277
|
}
|
|
231
|
-
|
|
278
|
+
requireValidSource() {
|
|
232
279
|
return (control) => {
|
|
233
|
-
const url = control.get(
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const error = { required: true };
|
|
241
|
-
uploadBinary.setErrors(Object.assign({}, uploadBinary.errors || {}, error));
|
|
242
|
-
Object.assign(errors, error);
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
// remove previous error
|
|
246
|
-
this.removeErrors(uploadBinary, ['required']);
|
|
280
|
+
const url = control.get('contentUrl');
|
|
281
|
+
const droppedFile = control.get('droppedFile');
|
|
282
|
+
// Write mode - always valid, editor content handled separately
|
|
283
|
+
if (this.uploadChoice === MarkdownSourceType.WRITE) {
|
|
284
|
+
url.setErrors(null);
|
|
285
|
+
droppedFile.setErrors(null);
|
|
286
|
+
return null;
|
|
247
287
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
288
|
+
// Clear required errors on inactive controls, set on active if empty
|
|
289
|
+
if (this.uploadChoice === MarkdownSourceType.URL) {
|
|
290
|
+
this.clearRequiredError(droppedFile);
|
|
291
|
+
if (!url.value) {
|
|
292
|
+
url.setErrors({ ...url.errors, required: true });
|
|
293
|
+
return { required: true };
|
|
294
|
+
}
|
|
295
|
+
this.clearRequiredError(url);
|
|
253
296
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
297
|
+
if (this.uploadChoice === MarkdownSourceType.UPLOAD) {
|
|
298
|
+
this.clearRequiredError(url);
|
|
299
|
+
if (!droppedFile.value) {
|
|
300
|
+
droppedFile.setErrors({ ...droppedFile.errors, required: true });
|
|
301
|
+
return { required: true };
|
|
302
|
+
}
|
|
303
|
+
this.clearRequiredError(droppedFile);
|
|
257
304
|
}
|
|
258
|
-
return
|
|
305
|
+
return null;
|
|
259
306
|
};
|
|
260
307
|
}
|
|
261
|
-
|
|
262
|
-
if (
|
|
263
|
-
|
|
308
|
+
clearRequiredError(control) {
|
|
309
|
+
if (control?.errors?.required) {
|
|
310
|
+
const { required: _, ...rest } = control.errors;
|
|
311
|
+
control.setErrors(Object.keys(rest).length ? rest : null);
|
|
264
312
|
}
|
|
265
|
-
let removedError = false;
|
|
266
|
-
for (const error of errors) {
|
|
267
|
-
if (control.errors[error]) {
|
|
268
|
-
removedError = true;
|
|
269
|
-
delete control.errors[error];
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
if (removedError) {
|
|
273
|
-
control.setErrors(Object.keys(control.errors).length ? Object.assign({}, control.errors) : null);
|
|
274
|
-
}
|
|
275
|
-
return removedError;
|
|
276
313
|
}
|
|
277
314
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MarkdownWidgetConfigComponent, deps: [{ token: i1$1.FormBuilder }, { token: i1$1.NgForm }, { token: i1.AlertService }, { token: MarkdownWidgetService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
278
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MarkdownWidgetConfigComponent, isStandalone: true, selector: "c8y-markdown-widget-config", inputs: { config: "config" }, viewQueries: [{ propertyName: "markdownPreviewTemplate", first: true, predicate: ["markdownPreview"], descendants: true }], ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Source' | translate }}</legend>\n <form [formGroup]=\"formGroup\">\n <div class=\"form-group\">\n <label\n class=\"c8y-radio radio-inline\"\n title=\"{{ 'Upload a binary' | translate }}\"\n >\n <input\n name=\"uploadChoice\"\n type=\"radio\"\n value=\"
|
|
315
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MarkdownWidgetConfigComponent, isStandalone: true, selector: "c8y-markdown-widget-config", inputs: { config: "config" }, viewQueries: [{ propertyName: "markdownPreviewTemplate", first: true, predicate: ["markdownPreview"], descendants: true }], ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Source' | translate }}</legend>\n <form [formGroup]=\"formGroup\">\n <div class=\"form-group\">\n <label\n class=\"c8y-radio radio-inline\"\n title=\"{{ 'Write Markdown' | translate }}\"\n >\n <input\n name=\"uploadChoice\"\n type=\"radio\"\n [value]=\"MarkdownSourceType.WRITE\"\n formControlName=\"uploadChoice\"\n (change)=\"onChange(MarkdownSourceType.WRITE)\"\n />\n <span></span>\n <span>{{ 'Write Markdown' | translate }}</span>\n </label>\n <label\n class=\"c8y-radio radio-inline m-l-8\"\n title=\"{{ 'Upload a binary' | translate }}\"\n >\n <input\n name=\"uploadChoice\"\n type=\"radio\"\n [value]=\"MarkdownSourceType.UPLOAD\"\n formControlName=\"uploadChoice\"\n (change)=\"onChange(MarkdownSourceType.UPLOAD)\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label\n class=\"c8y-radio radio-inline m-l-8\"\n title=\"{{ 'Provide a file path' | translate }}\"\n >\n <input\n name=\"uploadChoice\"\n type=\"radio\"\n [value]=\"MarkdownSourceType.URL\"\n formControlName=\"uploadChoice\"\n (change)=\"onChange(MarkdownSourceType.URL)\"\n />\n <span></span>\n <span>{{ 'Provide a file path' | translate }}</span>\n </label>\n </div>\n @switch (uploadChoice) {\n @case (MarkdownSourceType.WRITE) {\n <c8y-editor\n class=\"d-block\"\n style=\"height: 300px\"\n [ngModel]=\"editorContent\"\n (ngModelChange)=\"onEditorChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [editorOptions]=\"{\n language: 'markdown',\n tabSize: 2,\n insertSpaces: true,\n minimap: { enabled: false },\n wordWrap: 'on'\n }\"\n ></c8y-editor>\n }\n @case (MarkdownSourceType.UPLOAD) {\n <c8y-form-group class=\"m-b-24\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n formControlName=\"droppedFile\"\n [maxAllowedFiles]=\"1\"\n [accept]=\"'md'\"\n ></c8y-drop-area>\n </c8y-form-group>\n }\n @case (MarkdownSourceType.URL) {\n <c8y-form-group class=\"m-b-24\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n type=\"text\"\n formControlName=\"contentUrl\"\n />\n </div>\n </c8y-form-group>\n }\n }\n </form>\n</fieldset>\n\n<ng-template #markdownPreview>\n @if (previewMarkdown$ | async; as previewMarkdown) {\n <div\n class=\"p-16 p-t-0 markdown-content fit-h overflow-auto\"\n [innerHTML]=\"previewMarkdown | markdownToHtml | async\"\n ></div>\n } @else {\n <div class=\"fit-h d-flex d-col j-c-center a-i-center\">\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No content to preview' | translate\"\n [subtitle]=\"\n 'Write Markdown, upload a file, or provide a URL to see the preview' | translate\n \"\n [horizontal]=\"false\"\n ></c8y-ui-empty-state>\n </div>\n }\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.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: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { 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: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }] }); }
|
|
279
316
|
}
|
|
280
317
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MarkdownWidgetConfigComponent, decorators: [{
|
|
281
318
|
type: Component,
|
|
282
319
|
args: [{ selector: 'c8y-markdown-widget-config', standalone: true, imports: [
|
|
283
320
|
ReactiveFormsModule,
|
|
321
|
+
FormsModule,
|
|
284
322
|
AsyncPipe,
|
|
285
323
|
C8yTranslatePipe,
|
|
286
324
|
MarkdownToHtmlPipe,
|
|
287
325
|
FormGroupComponent,
|
|
288
326
|
DropAreaComponent,
|
|
289
327
|
EmptyStateComponent,
|
|
290
|
-
IconDirective
|
|
291
|
-
|
|
328
|
+
IconDirective,
|
|
329
|
+
EditorComponent
|
|
330
|
+
], template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Source' | translate }}</legend>\n <form [formGroup]=\"formGroup\">\n <div class=\"form-group\">\n <label\n class=\"c8y-radio radio-inline\"\n title=\"{{ 'Write Markdown' | translate }}\"\n >\n <input\n name=\"uploadChoice\"\n type=\"radio\"\n [value]=\"MarkdownSourceType.WRITE\"\n formControlName=\"uploadChoice\"\n (change)=\"onChange(MarkdownSourceType.WRITE)\"\n />\n <span></span>\n <span>{{ 'Write Markdown' | translate }}</span>\n </label>\n <label\n class=\"c8y-radio radio-inline m-l-8\"\n title=\"{{ 'Upload a binary' | translate }}\"\n >\n <input\n name=\"uploadChoice\"\n type=\"radio\"\n [value]=\"MarkdownSourceType.UPLOAD\"\n formControlName=\"uploadChoice\"\n (change)=\"onChange(MarkdownSourceType.UPLOAD)\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label\n class=\"c8y-radio radio-inline m-l-8\"\n title=\"{{ 'Provide a file path' | translate }}\"\n >\n <input\n name=\"uploadChoice\"\n type=\"radio\"\n [value]=\"MarkdownSourceType.URL\"\n formControlName=\"uploadChoice\"\n (change)=\"onChange(MarkdownSourceType.URL)\"\n />\n <span></span>\n <span>{{ 'Provide a file path' | translate }}</span>\n </label>\n </div>\n @switch (uploadChoice) {\n @case (MarkdownSourceType.WRITE) {\n <c8y-editor\n class=\"d-block\"\n style=\"height: 300px\"\n [ngModel]=\"editorContent\"\n (ngModelChange)=\"onEditorChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [editorOptions]=\"{\n language: 'markdown',\n tabSize: 2,\n insertSpaces: true,\n minimap: { enabled: false },\n wordWrap: 'on'\n }\"\n ></c8y-editor>\n }\n @case (MarkdownSourceType.UPLOAD) {\n <c8y-form-group class=\"m-b-24\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n formControlName=\"droppedFile\"\n [maxAllowedFiles]=\"1\"\n [accept]=\"'md'\"\n ></c8y-drop-area>\n </c8y-form-group>\n }\n @case (MarkdownSourceType.URL) {\n <c8y-form-group class=\"m-b-24\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n type=\"text\"\n formControlName=\"contentUrl\"\n />\n </div>\n </c8y-form-group>\n }\n }\n </form>\n</fieldset>\n\n<ng-template #markdownPreview>\n @if (previewMarkdown$ | async; as previewMarkdown) {\n <div\n class=\"p-16 p-t-0 markdown-content fit-h overflow-auto\"\n [innerHTML]=\"previewMarkdown | markdownToHtml | async\"\n ></div>\n } @else {\n <div class=\"fit-h d-flex d-col j-c-center a-i-center\">\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No content to preview' | translate\"\n [subtitle]=\"\n 'Write Markdown, upload a file, or provide a URL to see the preview' | translate\n \"\n [horizontal]=\"false\"\n ></c8y-ui-empty-state>\n </div>\n }\n</ng-template>\n" }]
|
|
292
331
|
}], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: i1$1.NgForm }, { type: i1.AlertService }, { type: MarkdownWidgetService }], propDecorators: { config: [{
|
|
293
332
|
type: Input
|
|
294
333
|
}], markdownPreviewTemplate: [{
|
|
@@ -301,7 +340,10 @@ class MarkdownWidgetViewComponent {
|
|
|
301
340
|
this.markdownWidgetService = markdownWidgetService;
|
|
302
341
|
}
|
|
303
342
|
async ngOnInit() {
|
|
304
|
-
if (this.config.
|
|
343
|
+
if (this.config.markdownContent) {
|
|
344
|
+
this.markdown = this.config.markdownContent;
|
|
345
|
+
}
|
|
346
|
+
else if (this.config.markdownBinaryId) {
|
|
305
347
|
const file = await this.markdownWidgetService.getFile(this.config.markdownBinaryId);
|
|
306
348
|
this.markdown = await file?.text();
|
|
307
349
|
}
|
|
@@ -323,5 +365,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
323
365
|
* Generated bundle index. Do not edit.
|
|
324
366
|
*/
|
|
325
367
|
|
|
326
|
-
export { MarkdownWidgetConfigComponent, MarkdownWidgetService, MarkdownWidgetViewComponent };
|
|
368
|
+
export { MarkdownSourceType, MarkdownWidgetConfigComponent, MarkdownWidgetService, MarkdownWidgetViewComponent };
|
|
327
369
|
//# sourceMappingURL=c8y-ngx-components-widgets-implementations-markdown.mjs.map
|