@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
239 lines (233 loc) • 18 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Input, Component } from '@angular/core';
import * as i2 from '@c8y/ngx-components';
import { gettext, C8yValidators, CoreModule, MarkdownToHtmlPipe } from '@c8y/ngx-components';
import * as i1 from '@angular/forms';
import { Validators, ReactiveFormsModule } from '@angular/forms';
import * as i2$1 from '@c8y/client';
import * as i3 from '@ngx-translate/core';
import * as i4 from '@angular/common';
import { AsyncPipe } from '@angular/common';
class MarkdownWidgetService {
constructor(fileService, inventory, binary, alert, translate) {
this.fileService = fileService;
this.inventory = inventory;
this.binary = binary;
this.alert = alert;
this.translate = translate;
}
async getFile(markdownBinaryId) {
if (!markdownBinaryId) {
return null;
}
try {
const { data: markdownBinaryMo } = await this.inventory.detail(markdownBinaryId);
const file = await this.fileService.getFile(markdownBinaryMo);
return file;
}
catch (e) {
const text = this.translate.instant(gettext('Unable to retrieve binary with ID: {{ markdownBinaryId }}'), { markdownBinaryId });
this.alert.danger(text, e?.data);
}
return null;
}
async uploadFile(file) {
const { data: mo } = await this.binary.create(file);
return mo.id;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownWidgetService, deps: [{ token: i2.FilesService }, { token: i2$1.InventoryService }, { token: i2$1.InventoryBinaryService }, { token: i2.AlertService }, { token: i3.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownWidgetService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownWidgetService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i2.FilesService }, { type: i2$1.InventoryService }, { type: i2$1.InventoryBinaryService }, { type: i2.AlertService }, { type: i3.TranslateService }] });
class MarkdownWidgetConfigComponent {
constructor(formBuilder, form, alert, markdownService) {
this.formBuilder = formBuilder;
this.form = form;
this.alert = alert;
this.markdownService = markdownService;
this.uploadChoice = 'uploadUrl';
this.loading = false;
}
async onBeforeSave(config) {
if (this.formGroup.invalid) {
return false;
}
if (this.uploadChoice === 'uploadUrl') {
Object.assign(config, {
contentUrl: this.formGroup.value.contentUrl,
markdownBinaryId: null
});
return true;
}
const fileFromForm = this.getFileFromFormValue(this.formGroup.value);
if (fileFromForm && fileFromForm !== this.fileFromConfig) {
try {
const markdownBinaryId = await this.markdownService.uploadFile(fileFromForm);
Object.assign(config, { markdownBinaryId, contentUrl: null });
return true;
}
catch (e) {
this.alert.danger(gettext('Unable to upload Markdown file.'), e?.data);
return false;
}
}
if (!fileFromForm) {
Object.assign(config, { contentUrl: '/readme.md', markdownBinaryId: null });
}
return true;
}
async ngOnInit() {
this.initForm();
if (this.config.markdownBinaryId) {
this.uploadChoice = 'uploadBinary';
this.fileFromConfig = await this.markdownService.getFile(this.config.markdownBinaryId);
this.formGroup.patchValue({
droppedFile: [{ file: this.fileFromConfig, name: this.fileFromConfig.name }]
});
}
}
onChange(value) {
this.uploadChoice = value;
this.formGroup.controls['uploadChoice'].patchValue(value);
}
getFileFromFormValue(formValue) {
const binary = formValue?.droppedFile || [];
return binary[0]?.file || null;
}
initForm() {
this.formGroup = this.formBuilder.group({
contentUrl: ['', [Validators.maxLength(2000)]],
droppedFile: [
null,
[
Validators.minLength(1),
Validators.maxLength(1),
C8yValidators.filesValidator({ maximumFileSizeInKb: 1000 })
]
],
uploadChoice: [this.config.markdownBinaryId ? 'uploadBinary' : 'uploadUrl', []]
}, { validators: this.requireEitherBinaryOrUrl() });
this.form.form.addControl('config', this.formGroup);
this.formGroup.patchValue(this.config);
}
requireEitherBinaryOrUrl() {
return (control) => {
const url = control.get(`contentUrl`);
const uploadBinary = control.get(`droppedFile`);
const urlDefined = url && url.value !== undefined && url.value !== null;
const uploadBinaryDefined = uploadBinary && uploadBinary.value !== undefined && uploadBinary.value !== null;
const errors = {};
if (this.uploadChoice === 'uploadBinary' && !uploadBinaryDefined) {
// sets error
const error = { required: true };
uploadBinary.setErrors(Object.assign({}, uploadBinary.errors || {}, error));
Object.assign(errors, error);
}
else {
// remove previous error
this.removeErrors(uploadBinary, ['required']);
}
if (this.uploadChoice === 'uploadUrl' && (!urlDefined || url.value === '')) {
// sets error
const error = { required: true };
url.setErrors(Object.assign({}, url.errors || {}, error));
Object.assign(errors, error);
}
else {
// remove previous error
this.removeErrors(url, ['required']);
}
return Object.keys(errors).length ? errors : null;
};
}
removeErrors(control, errors) {
if (!control || !control.errors) {
return false;
}
let removedError = false;
for (const error of errors) {
if (control.errors[error]) {
removedError = true;
delete control.errors[error];
}
}
if (removedError) {
control.setErrors(Object.keys(control.errors).length ? Object.assign({}, control.errors) : null);
}
return removedError;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownWidgetConfigComponent, deps: [{ token: i1.FormBuilder }, { token: i1.NgForm }, { token: i2.AlertService }, { token: MarkdownWidgetService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: MarkdownWidgetConfigComponent, isStandalone: true, selector: "c8y-markdown-widget-config", inputs: { config: "config" }, ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Source' | translate }}</legend>\n <form [formGroup]=\"formGroup\" class=\"\">\n <div class=\"form-group\">\n <label title=\"{{ 'Upload a binary' | translate }}\" class=\"c8y-radio radio-inline\">\n <input\n #radio\n formControlName=\"uploadChoice\"\n type=\"radio\"\n value=\"uploadBinary\"\n name=\"uploadChoice\"\n (change)=\"onChange($event.target.value)\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label title=\"{{ 'Provide a file path' | translate }}\" class=\"c8y-radio radio-inline m-l-8\">\n <input\n #radio\n formControlName=\"uploadChoice\"\n type=\"radio\"\n value=\"uploadUrl\"\n name=\"uploadChoice\"\n (change)=\"onChange($event.target.value)\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n </label>\n </div>\n <ng-container [ngSwitch]=\"uploadChoice\">\n <div *ngSwitchCase=\"'uploadBinary'\">\n <c8y-form-group class=\"m-b-8\">\n <c8y-drop-area\n formControlName=\"droppedFile\"\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n [maxAllowedFiles]=\"1\"\n [accept]=\"'md'\"\n ></c8y-drop-area>\n </c8y-form-group>\n </div>\n <div *ngSwitchCase=\"'uploadUrl'\">\n <c8y-form-group class=\"m-b-8\">\n <div class=\"m-b-4 p-b-8\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n type=\"text\"\n class=\"form-control\"\n formControlName=\"contentUrl\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n />\n </div>\n </div>\n </c8y-form-group>\n </div>\n </ng-container>\n </form>\n</fieldset>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: i2.DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "maxFileSizeInMegaBytes", "accept"], outputs: ["dropped"] }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownWidgetConfigComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-markdown-widget-config', standalone: true, imports: [CoreModule, ReactiveFormsModule], template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Source' | translate }}</legend>\n <form [formGroup]=\"formGroup\" class=\"\">\n <div class=\"form-group\">\n <label title=\"{{ 'Upload a binary' | translate }}\" class=\"c8y-radio radio-inline\">\n <input\n #radio\n formControlName=\"uploadChoice\"\n type=\"radio\"\n value=\"uploadBinary\"\n name=\"uploadChoice\"\n (change)=\"onChange($event.target.value)\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label title=\"{{ 'Provide a file path' | translate }}\" class=\"c8y-radio radio-inline m-l-8\">\n <input\n #radio\n formControlName=\"uploadChoice\"\n type=\"radio\"\n value=\"uploadUrl\"\n name=\"uploadChoice\"\n (change)=\"onChange($event.target.value)\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n </label>\n </div>\n <ng-container [ngSwitch]=\"uploadChoice\">\n <div *ngSwitchCase=\"'uploadBinary'\">\n <c8y-form-group class=\"m-b-8\">\n <c8y-drop-area\n formControlName=\"droppedFile\"\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n [maxAllowedFiles]=\"1\"\n [accept]=\"'md'\"\n ></c8y-drop-area>\n </c8y-form-group>\n </div>\n <div *ngSwitchCase=\"'uploadUrl'\">\n <c8y-form-group class=\"m-b-8\">\n <div class=\"m-b-4 p-b-8\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n type=\"text\"\n class=\"form-control\"\n formControlName=\"contentUrl\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n />\n </div>\n </div>\n </c8y-form-group>\n </div>\n </ng-container>\n </form>\n</fieldset>\n" }]
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i1.NgForm }, { type: i2.AlertService }, { type: MarkdownWidgetService }], propDecorators: { config: [{
type: Input
}] } });
class MarkdownWidgetViewComponent {
constructor(appState, client, markdownWidgetService) {
this.appState = appState;
this.client = client;
this.markdownWidgetService = markdownWidgetService;
this.headers = { 'Content-Type': 'text/markdown', responseType: 'blob' };
}
async ngOnInit() {
this.contextPath = this.appState.state.app.contextPath;
if (this.config.markdownBinaryId) {
const readmeContent = await (await this.markdownWidgetService.getFile(this.config.markdownBinaryId)).text();
this.markdown = readmeContent;
}
else if (this.config.contentUrl?.toLowerCase() === '/readme.md') {
this.markdown = await this.getReadmeFileContent();
}
else {
this.setContentFromUrl(this.config.contentUrl);
}
}
setContentFromUrl(url) {
const req = new XMLHttpRequest();
req.onreadystatechange = () => this.render(req);
req.addEventListener('load', () => this.render(req));
req.open('GET', url);
req.responseType = 'text';
req.setRequestHeader('Accept', 'text/html');
req.send();
}
async render(req) {
if (req.readyState === 4 && req.status === 200) {
this.markdown = req.response;
}
}
async getReadmeFileContent() {
const readmeFile = await this.getReadmeFile();
if (readmeFile.status === 200) {
return await readmeFile.text();
}
return '';
}
async getReadmeFile() {
const options = {
method: 'GET',
headers: this.headers
};
const result = await this.client.fetch(`/apps/${this.contextPath}${this.config.contentUrl}`, options);
return result;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownWidgetViewComponent, deps: [{ token: i2.AppStateService }, { token: i2$1.FetchClient }, { token: MarkdownWidgetService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: MarkdownWidgetViewComponent, isStandalone: true, selector: "c8y-markdown-widget-view", inputs: { config: "config" }, ngImport: i0, template: "<div id=\"helpContent\" class=\"p-16 p-t-0 markdown-content\" [innerHTML]=\"markdown | markdownToHtml | async\"></div>\n", dependencies: [{ kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownWidgetViewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-markdown-widget-view', standalone: true, imports: [MarkdownToHtmlPipe, AsyncPipe], template: "<div id=\"helpContent\" class=\"p-16 p-t-0 markdown-content\" [innerHTML]=\"markdown | markdownToHtml | async\"></div>\n" }]
}], ctorParameters: () => [{ type: i2.AppStateService }, { type: i2$1.FetchClient }, { type: MarkdownWidgetService }], propDecorators: { config: [{
type: Input
}] } });
/**
* Generated bundle index. Do not edit.
*/
export { MarkdownWidgetConfigComponent, MarkdownWidgetService, MarkdownWidgetViewComponent };
//# sourceMappingURL=c8y-ngx-components-widgets-implementations-markdown.mjs.map