spiderly 19.5.3 → 19.5.4-preview.1
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/fesm2022/spiderly.mjs +212 -72
- package/fesm2022/spiderly.mjs.map +1 -1
- package/lib/components/auth/partials/auth.component.d.ts +2 -3
- package/lib/components/base-form/base-form copy.d.ts +130 -9
- package/lib/components/spiderly-form-control/spiderly-form-control.d.ts +8 -2
- package/lib/controls/spiderly-editor/spiderly-editor.component.d.ts +7 -2
- package/lib/controls/spiderly-file/spiderly-file.component.d.ts +7 -3
- package/lib/entities/security-entities.d.ts +4 -4
- package/lib/services/base-form.service.d.ts +2 -4
- package/lib/services/config.service.base.d.ts +1 -0
- package/lib/services/helper-functions.d.ts +5 -1
- package/lib/services/validator-abstract.service.d.ts +5 -2
- package/package.json +1 -1
- package/public-api.d.ts +0 -2
- package/lib/entities/mime-type.d.ts +0 -11
- package/lib/services/translate-labels-abstract.service.d.ts +0 -7
package/fesm2022/spiderly.mjs
CHANGED
|
@@ -209,7 +209,7 @@ class SpiderlyFormGroup extends FormGroup {
|
|
|
209
209
|
constructor(controls) {
|
|
210
210
|
super(controls);
|
|
211
211
|
this.trackingId = crypto.randomUUID();
|
|
212
|
-
|
|
212
|
+
// TODO: Delete controlNamesFromHtml and add UIDoNotGenerate flag into ng entity generator, we shouldn't even add those into parentFormGroup
|
|
213
213
|
this.controlNamesFromHtml = [];
|
|
214
214
|
this.getControl = (formControlName) => {
|
|
215
215
|
if (this.controlNamesFromHtml.findIndex((x) => x === formControlName) === -1)
|
|
@@ -285,10 +285,10 @@ class SpiderlyFormArray extends FormArray {
|
|
|
285
285
|
class ValidatorAbstractService {
|
|
286
286
|
constructor(translocoService) {
|
|
287
287
|
this.translocoService = translocoService;
|
|
288
|
-
this.
|
|
288
|
+
this.notEmpty = (control) => {
|
|
289
289
|
const validator = () => {
|
|
290
290
|
const value = control.value;
|
|
291
|
-
const notEmptyRule = typeof value !== 'undefined' && value !== null && value
|
|
291
|
+
const notEmptyRule = typeof value !== 'undefined' && value !== null && value !== '';
|
|
292
292
|
const arrayValid = notEmptyRule;
|
|
293
293
|
return arrayValid
|
|
294
294
|
? null
|
|
@@ -296,25 +296,32 @@ class ValidatorAbstractService {
|
|
|
296
296
|
};
|
|
297
297
|
validator.hasNotEmptyRule = true;
|
|
298
298
|
control.required = true;
|
|
299
|
-
|
|
299
|
+
control.validator = validator;
|
|
300
|
+
control.updateValueAndValidity();
|
|
300
301
|
};
|
|
301
|
-
|
|
302
|
+
/** Validates that a SpiderlyFormArray (collection of form controls/groups) is not empty. */
|
|
303
|
+
this.isFormArrayEmpty = (control) => {
|
|
302
304
|
const validator = () => {
|
|
303
|
-
const value = control
|
|
304
|
-
const notEmptyRule = typeof value !== 'undefined' && value !== null && value !==
|
|
305
|
+
const value = control;
|
|
306
|
+
const notEmptyRule = typeof value !== 'undefined' && value !== null && value.length !== 0;
|
|
305
307
|
const arrayValid = notEmptyRule;
|
|
306
308
|
return arrayValid
|
|
307
309
|
? null
|
|
308
|
-
: {
|
|
310
|
+
: {
|
|
311
|
+
_: this.translocoService.translate('ListCanNotBeEmpty', {
|
|
312
|
+
value: control.labelForDisplay,
|
|
313
|
+
}),
|
|
314
|
+
};
|
|
309
315
|
};
|
|
310
316
|
validator.hasNotEmptyRule = true;
|
|
311
317
|
control.required = true;
|
|
312
|
-
control.validator
|
|
318
|
+
control.setValidators(validator);
|
|
313
319
|
control.updateValueAndValidity();
|
|
314
320
|
};
|
|
315
|
-
|
|
321
|
+
/** Validates that a SpiderlyFormControl holding an array value (e.g., multi-select dropdown) is not empty. */
|
|
322
|
+
this.isArrayEmpty = (control) => {
|
|
316
323
|
const validator = () => {
|
|
317
|
-
const value = control;
|
|
324
|
+
const value = control.value;
|
|
318
325
|
const notEmptyRule = typeof value !== 'undefined' && value !== null && value.length !== 0;
|
|
319
326
|
const arrayValid = notEmptyRule;
|
|
320
327
|
return arrayValid
|
|
@@ -743,10 +750,36 @@ class SpiderlyEditorComponent extends BaseControl {
|
|
|
743
750
|
constructor(translocoService) {
|
|
744
751
|
super(translocoService);
|
|
745
752
|
this.translocoService = translocoService;
|
|
753
|
+
this.objectId = 0;
|
|
746
754
|
}
|
|
747
755
|
ngOnInit() {
|
|
748
756
|
super.ngOnInit();
|
|
749
757
|
}
|
|
758
|
+
onEditorInit(event) {
|
|
759
|
+
const quill = event.editor;
|
|
760
|
+
if (this.uploadImageMethod) {
|
|
761
|
+
const toolbar = quill.getModule('toolbar');
|
|
762
|
+
toolbar.addHandler('image', () => this.imageHandler(quill));
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
imageHandler(quill) {
|
|
766
|
+
const input = document.createElement('input');
|
|
767
|
+
input.setAttribute('type', 'file');
|
|
768
|
+
input.setAttribute('accept', 'image/*');
|
|
769
|
+
input.click();
|
|
770
|
+
input.onchange = async () => {
|
|
771
|
+
const file = input.files[0];
|
|
772
|
+
if (file) {
|
|
773
|
+
const formData = new FormData();
|
|
774
|
+
formData.append('file', file, `${this.objectId}-${file.name}`);
|
|
775
|
+
this.uploadImageMethod(formData).subscribe((imageUrl) => {
|
|
776
|
+
const range = quill.getSelection(true);
|
|
777
|
+
quill.insertEmbed(range.index, 'image', imageUrl);
|
|
778
|
+
quill.setSelection(range.index + 1);
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
}
|
|
750
783
|
onClick() {
|
|
751
784
|
let editableArea = this.editor.el.nativeElement.querySelector('.ql-editor');
|
|
752
785
|
editableArea.onblur = () => {
|
|
@@ -765,7 +798,7 @@ class SpiderlyEditorComponent extends BaseControl {
|
|
|
765
798
|
};
|
|
766
799
|
}
|
|
767
800
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyEditorComponent, deps: [{ token: i1.TranslocoService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
768
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.13", type: SpiderlyEditorComponent, isStandalone: true, selector: "spiderly-editor", viewQueries: [{ propertyName: "editor", first: true, predicate: Editor, descendants: true }, { propertyName: "tooltip", first: true, predicate: Tooltip, descendants: true }], usesInheritance: true, ngImport: i0, template: "<!-- Can't put (onBlur) in this control -->\n\n<div style=\"display: flex; flex-direction: column; gap: 0.5rem\">\n <div *ngIf=\"getTranslatedLabel() != '' && getTranslatedLabel() != null\">\n <label>{{ getTranslatedLabel() }}</label>\n <required *ngIf=\"control?.required && showRequired\"></required>\n </div>\n\n <!-- Disable doesn't work on this control -->\n <p-editor\n *ngIf=\"control\"\n [formControl]=\"control\"\n [pTooltip]=\"getValidationErrrorMessages()\"\n [tooltipEvent]=\"errorMessageTooltipEvent\"\n tooltipPosition=\"bottom\"\n [tooltipDisabled]=\"control.valid\"\n tooltipStyleClass=\"spiderly-tooltip-invalid\"\n [readonly]=\"control.disabled\"\n [class]=\"control.invalid && control.dirty ? 'control-error-border' : ''\"\n [id]=\"control.label\"\n [placeholder]=\"placeholder\"\n (click)=\"onClick()\"\n [style]=\"{ height: '320px' }\"\n ></p-editor>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: EditorModule }, { kind: "component", type: i4$8.Editor, selector: "p-editor", inputs: ["style", "styleClass", "placeholder", "formats", "modules", "bounds", "scrollingContainer", "debug", "readonly"], outputs: ["onInit", "onTextChange", "onSelectionChange"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: RequiredComponent, selector: "required" }] }); }
|
|
801
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.13", type: SpiderlyEditorComponent, isStandalone: true, selector: "spiderly-editor", inputs: { uploadImageMethod: "uploadImageMethod", objectId: "objectId" }, viewQueries: [{ propertyName: "editor", first: true, predicate: Editor, descendants: true }, { propertyName: "tooltip", first: true, predicate: Tooltip, descendants: true }], usesInheritance: true, ngImport: i0, template: "<!-- Can't put (onBlur) in this control -->\n\n<div style=\"display: flex; flex-direction: column; gap: 0.5rem; padding: 0 1px\">\n <div *ngIf=\"getTranslatedLabel() != '' && getTranslatedLabel() != null\">\n <label>{{ getTranslatedLabel() }}</label>\n <required *ngIf=\"control?.required && showRequired\"></required>\n </div>\n\n <!-- Disable doesn't work on this control -->\n <p-editor\n *ngIf=\"control\"\n [formControl]=\"control\"\n [pTooltip]=\"getValidationErrrorMessages()\"\n [tooltipEvent]=\"errorMessageTooltipEvent\"\n tooltipPosition=\"bottom\"\n [tooltipDisabled]=\"control.valid\"\n tooltipStyleClass=\"spiderly-tooltip-invalid\"\n [readonly]=\"control.disabled\"\n [class]=\"control.invalid && control.dirty ? 'control-error-border' : ''\"\n [id]=\"control.label\"\n [placeholder]=\"placeholder\"\n (click)=\"onClick()\"\n (onInit)=\"onEditorInit($event)\"\n [style]=\"{ height: '320px' }\"\n ></p-editor>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: EditorModule }, { kind: "component", type: i4$8.Editor, selector: "p-editor", inputs: ["style", "styleClass", "placeholder", "formats", "modules", "bounds", "scrollingContainer", "debug", "readonly"], outputs: ["onInit", "onTextChange", "onSelectionChange"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: RequiredComponent, selector: "required" }] }); }
|
|
769
802
|
}
|
|
770
803
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyEditorComponent, decorators: [{
|
|
771
804
|
type: Component,
|
|
@@ -776,13 +809,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
776
809
|
EditorModule,
|
|
777
810
|
TooltipModule,
|
|
778
811
|
RequiredComponent,
|
|
779
|
-
], template: "<!-- Can't put (onBlur) in this control -->\n\n<div style=\"display: flex; flex-direction: column; gap: 0.5rem\">\n <div *ngIf=\"getTranslatedLabel() != '' && getTranslatedLabel() != null\">\n <label>{{ getTranslatedLabel() }}</label>\n <required *ngIf=\"control?.required && showRequired\"></required>\n </div>\n\n <!-- Disable doesn't work on this control -->\n <p-editor\n *ngIf=\"control\"\n [formControl]=\"control\"\n [pTooltip]=\"getValidationErrrorMessages()\"\n [tooltipEvent]=\"errorMessageTooltipEvent\"\n tooltipPosition=\"bottom\"\n [tooltipDisabled]=\"control.valid\"\n tooltipStyleClass=\"spiderly-tooltip-invalid\"\n [readonly]=\"control.disabled\"\n [class]=\"control.invalid && control.dirty ? 'control-error-border' : ''\"\n [id]=\"control.label\"\n [placeholder]=\"placeholder\"\n (click)=\"onClick()\"\n [style]=\"{ height: '320px' }\"\n ></p-editor>\n</div>\n" }]
|
|
812
|
+
], template: "<!-- Can't put (onBlur) in this control -->\n\n<div style=\"display: flex; flex-direction: column; gap: 0.5rem; padding: 0 1px\">\n <div *ngIf=\"getTranslatedLabel() != '' && getTranslatedLabel() != null\">\n <label>{{ getTranslatedLabel() }}</label>\n <required *ngIf=\"control?.required && showRequired\"></required>\n </div>\n\n <!-- Disable doesn't work on this control -->\n <p-editor\n *ngIf=\"control\"\n [formControl]=\"control\"\n [pTooltip]=\"getValidationErrrorMessages()\"\n [tooltipEvent]=\"errorMessageTooltipEvent\"\n tooltipPosition=\"bottom\"\n [tooltipDisabled]=\"control.valid\"\n tooltipStyleClass=\"spiderly-tooltip-invalid\"\n [readonly]=\"control.disabled\"\n [class]=\"control.invalid && control.dirty ? 'control-error-border' : ''\"\n [id]=\"control.label\"\n [placeholder]=\"placeholder\"\n (click)=\"onClick()\"\n (onInit)=\"onEditorInit($event)\"\n [style]=\"{ height: '320px' }\"\n ></p-editor>\n</div>\n" }]
|
|
780
813
|
}], ctorParameters: () => [{ type: i1.TranslocoService }], propDecorators: { editor: [{
|
|
781
814
|
type: ViewChild,
|
|
782
815
|
args: [Editor]
|
|
783
816
|
}], tooltip: [{
|
|
784
817
|
type: ViewChild,
|
|
785
818
|
args: [Tooltip]
|
|
819
|
+
}], uploadImageMethod: [{
|
|
820
|
+
type: Input
|
|
821
|
+
}], objectId: [{
|
|
822
|
+
type: Input
|
|
786
823
|
}] } });
|
|
787
824
|
|
|
788
825
|
class SpiderlyButtonBaseComponent {
|
|
@@ -887,6 +924,7 @@ function getMimeTypeForFileName(fileName) {
|
|
|
887
924
|
'.png': 'image/png',
|
|
888
925
|
'.webp': 'image/webp',
|
|
889
926
|
'.gif': 'image/gif',
|
|
927
|
+
'.svg': 'image/svg+xml',
|
|
890
928
|
'.pdf': 'application/pdf',
|
|
891
929
|
'.txt': 'text/plain',
|
|
892
930
|
'.html': 'text/html',
|
|
@@ -1033,7 +1071,7 @@ function toCommaSeparatedString(input) {
|
|
|
1033
1071
|
return stringList[0] ?? '';
|
|
1034
1072
|
}
|
|
1035
1073
|
}
|
|
1036
|
-
function
|
|
1074
|
+
function isFileImageType(mimeType) {
|
|
1037
1075
|
if (mimeType.startsWith('image/')) {
|
|
1038
1076
|
return true;
|
|
1039
1077
|
}
|
|
@@ -1136,6 +1174,16 @@ const primitiveArrayTypes = [
|
|
|
1136
1174
|
'Date[]',
|
|
1137
1175
|
'string[]',
|
|
1138
1176
|
];
|
|
1177
|
+
function getImageDimensions(file) {
|
|
1178
|
+
return new Promise((resolve) => {
|
|
1179
|
+
const img = new Image();
|
|
1180
|
+
img.onload = () => {
|
|
1181
|
+
resolve({ width: img.width, height: img.height });
|
|
1182
|
+
URL.revokeObjectURL(img.src);
|
|
1183
|
+
};
|
|
1184
|
+
img.src = URL.createObjectURL(file);
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1139
1187
|
|
|
1140
1188
|
class SpiderlyMessageService {
|
|
1141
1189
|
// TODO FT: nece da prikaze poruku ako je neki angular error koji se dogodi tek nakon api poziva
|
|
@@ -1221,7 +1269,7 @@ class SpiderlyFileComponent extends BaseControl {
|
|
|
1221
1269
|
}
|
|
1222
1270
|
filesSelected(event) {
|
|
1223
1271
|
const file = event.files[0];
|
|
1224
|
-
if (this.
|
|
1272
|
+
if (this.isFileImageType(file.type) &&
|
|
1225
1273
|
this.hasImageDimensionConstraints()) {
|
|
1226
1274
|
this.files = [];
|
|
1227
1275
|
this.validatorService
|
|
@@ -1240,10 +1288,17 @@ class SpiderlyFileComponent extends BaseControl {
|
|
|
1240
1288
|
this.emitFileSelected(file);
|
|
1241
1289
|
}
|
|
1242
1290
|
}
|
|
1243
|
-
emitFileSelected(file) {
|
|
1291
|
+
async emitFileSelected(file) {
|
|
1244
1292
|
const formData = new FormData();
|
|
1245
1293
|
formData.append('file', file, `${this.objectId}-${file.name}`);
|
|
1246
|
-
|
|
1294
|
+
let width;
|
|
1295
|
+
let height;
|
|
1296
|
+
if (this.isFileImageType(file.type)) {
|
|
1297
|
+
const dimensions = await getImageDimensions(file);
|
|
1298
|
+
width = dimensions.width;
|
|
1299
|
+
height = dimensions.height;
|
|
1300
|
+
}
|
|
1301
|
+
this.onFileSelected.next(new SpiderlyFileSelectEvent({ file, formData, width, height }));
|
|
1247
1302
|
}
|
|
1248
1303
|
hasImageDimensionConstraints() {
|
|
1249
1304
|
return this.imageWidth > 0 || this.imageHeight > 0;
|
|
@@ -1284,14 +1339,14 @@ class SpiderlyFileComponent extends BaseControl {
|
|
|
1284
1339
|
const file = new File([blob], fileName, { type: mimeType });
|
|
1285
1340
|
return file;
|
|
1286
1341
|
}
|
|
1287
|
-
|
|
1288
|
-
return
|
|
1342
|
+
isFileImageType(mimeType) {
|
|
1343
|
+
return isFileImageType(mimeType);
|
|
1289
1344
|
}
|
|
1290
1345
|
isExcelFileType(mimeType) {
|
|
1291
1346
|
return isExcelFileType(mimeType);
|
|
1292
1347
|
}
|
|
1293
1348
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyFileComponent, deps: [{ token: i1.TranslocoService }, { token: SpiderlyMessageService }, { token: ValidatorAbstractService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1294
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.13", type: SpiderlyFileComponent, isStandalone: true, selector: "spiderly-file", inputs: { objectId: "objectId", fileData: "fileData", acceptedFileTypes: "acceptedFileTypes", required: "required", multiple: "multiple", isCloudinaryFileData: "isCloudinaryFileData", imageWidth: "imageWidth", imageHeight: "imageHeight", files: "files" }, outputs: { onFileSelected: "onFileSelected", onFileRemoved: "onFileRemoved" }, usesInheritance: true, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div style=\"display: flex; flex-direction: column; gap: 0.5rem; padding: 1px\">\n <div *ngIf=\"getTranslatedLabel() != '' && getTranslatedLabel() != null\">\n <label>{{ getTranslatedLabel() }}</label>\n <!-- It's okay for this control, because for the custom uploads where we are not initializing the control from the backend, there is no need for formControl. -->\n <required *ngIf=\"control?.required || required\"></required>\n </div>\n\n <p-fileUpload\n [files]=\"files\"\n [disabled]=\"disabled\"\n [name]=\"control?.label ?? label\"\n [multiple]=\"multiple\"\n [accept]=\"acceptedFileTypesCommaSeparated\"\n [maxFileSize]=\"1000000\"\n (onSelect)=\"filesSelected($event)\"\n [class]=\"control?.invalid && control?.dirty ? 'control-error-border' : ''\"\n >\n <ng-template\n pTemplate=\"header\"\n let-files\n let-chooseCallback=\"chooseCallback\"\n let-clearCallback=\"clearCallback\"\n let-uploadCallback=\"uploadCallback\"\n >\n <div\n class=\"flex flex-wrap justify-content-between align-items-center flex-1 gap-2\"\n >\n <div class=\"flex gap-2\">\n <spiderly-button\n [disabled]=\"disabled\"\n (onClick)=\"choose($event, chooseCallback)\"\n icon=\"pi pi-upload\"\n [rounded]=\"true\"\n [outlined]=\"true\"\n />\n </div>\n </div>\n </ng-template>\n <ng-template\n pTemplate=\"content\"\n let-files\n let-removeFileCallback=\"removeFileCallback\"\n >\n <div *ngIf=\"files.length > 0\">\n <div class=\"flex justify-content-center p-0 gap-5\">\n <div\n *ngFor=\"let file of files; let index = index\"\n class=\"card m-0 px-3 py-3 flex flex-column align-items-center gap-3\"\n style=\"justify-content: center; overflow: hidden\"\n >\n <div *ngIf=\"
|
|
1349
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.13", type: SpiderlyFileComponent, isStandalone: true, selector: "spiderly-file", inputs: { objectId: "objectId", fileData: "fileData", acceptedFileTypes: "acceptedFileTypes", required: "required", multiple: "multiple", isCloudinaryFileData: "isCloudinaryFileData", imageWidth: "imageWidth", imageHeight: "imageHeight", files: "files" }, outputs: { onFileSelected: "onFileSelected", onFileRemoved: "onFileRemoved" }, usesInheritance: true, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div style=\"display: flex; flex-direction: column; gap: 0.5rem; padding: 1px\">\n <div *ngIf=\"getTranslatedLabel() != '' && getTranslatedLabel() != null\">\n <label>{{ getTranslatedLabel() }}</label>\n <!-- It's okay for this control, because for the custom uploads where we are not initializing the control from the backend, there is no need for formControl. -->\n <required *ngIf=\"control?.required || required\"></required>\n </div>\n\n <p-fileUpload\n [files]=\"files\"\n [disabled]=\"disabled\"\n [name]=\"control?.label ?? label\"\n [multiple]=\"multiple\"\n [accept]=\"acceptedFileTypesCommaSeparated\"\n [maxFileSize]=\"1000000\"\n (onSelect)=\"filesSelected($event)\"\n [class]=\"control?.invalid && control?.dirty ? 'control-error-border' : ''\"\n >\n <ng-template\n pTemplate=\"header\"\n let-files\n let-chooseCallback=\"chooseCallback\"\n let-clearCallback=\"clearCallback\"\n let-uploadCallback=\"uploadCallback\"\n >\n <div\n class=\"flex flex-wrap justify-content-between align-items-center flex-1 gap-2\"\n >\n <div class=\"flex gap-2\">\n <spiderly-button\n [disabled]=\"disabled\"\n (onClick)=\"choose($event, chooseCallback)\"\n icon=\"pi pi-upload\"\n [rounded]=\"true\"\n [outlined]=\"true\"\n />\n </div>\n </div>\n </ng-template>\n <ng-template\n pTemplate=\"content\"\n let-files\n let-removeFileCallback=\"removeFileCallback\"\n >\n <div *ngIf=\"files.length > 0\">\n <div class=\"flex justify-content-center p-0 gap-5\">\n <div\n *ngFor=\"let file of files; let index = index\"\n class=\"card m-0 px-3 py-3 flex flex-column align-items-center gap-3\"\n style=\"justify-content: center; overflow: hidden\"\n >\n <div *ngIf=\"isFileImageType(file.type)\" class=\"image-container\">\n <img role=\"presentation\" [src]=\"file.objectURL\" />\n </div>\n <div *ngIf=\"isExcelFileType(file.type)\" class=\"excel-container\">\n <div class=\"excel-details\">\n <i\n class=\"pi pi-file-excel\"\n style=\"color: green; margin-right: 4px\"\n ></i>\n <span class=\"file-name\">{{ file.name }}</span>\n </div>\n </div>\n <spiderly-button\n [disabled]=\"disabled\"\n icon=\"pi pi-times\"\n (onClick)=\"fileRemoved(removeFileCallback, index)\"\n [outlined]=\"true\"\n [rounded]=\"true\"\n severity=\"danger\"\n />\n </div>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"file\"> </ng-template>\n <ng-template pTemplate=\"empty\">\n <div class=\"flex align-items-center justify-content-center flex-column\">\n <i\n class=\"pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400 mt-3\"\n ></i>\n <p class=\"mt-4 mb-0\">{{ t(\"DragAndDropFilesHereToUpload\") }}</p>\n </div>\n </ng-template>\n </p-fileUpload>\n </div>\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i5$2.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "directive", type: i1$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: RequiredComponent, selector: "required" }, { kind: "component", type: SpiderlyButtonComponent, selector: "spiderly-button", inputs: ["type"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] }); }
|
|
1295
1350
|
}
|
|
1296
1351
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyFileComponent, decorators: [{
|
|
1297
1352
|
type: Component,
|
|
@@ -1303,7 +1358,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
1303
1358
|
RequiredComponent,
|
|
1304
1359
|
SpiderlyButtonComponent,
|
|
1305
1360
|
TranslocoDirective,
|
|
1306
|
-
], template: "<ng-container *transloco=\"let t\">\n <div style=\"display: flex; flex-direction: column; gap: 0.5rem; padding: 1px\">\n <div *ngIf=\"getTranslatedLabel() != '' && getTranslatedLabel() != null\">\n <label>{{ getTranslatedLabel() }}</label>\n <!-- It's okay for this control, because for the custom uploads where we are not initializing the control from the backend, there is no need for formControl. -->\n <required *ngIf=\"control?.required || required\"></required>\n </div>\n\n <p-fileUpload\n [files]=\"files\"\n [disabled]=\"disabled\"\n [name]=\"control?.label ?? label\"\n [multiple]=\"multiple\"\n [accept]=\"acceptedFileTypesCommaSeparated\"\n [maxFileSize]=\"1000000\"\n (onSelect)=\"filesSelected($event)\"\n [class]=\"control?.invalid && control?.dirty ? 'control-error-border' : ''\"\n >\n <ng-template\n pTemplate=\"header\"\n let-files\n let-chooseCallback=\"chooseCallback\"\n let-clearCallback=\"clearCallback\"\n let-uploadCallback=\"uploadCallback\"\n >\n <div\n class=\"flex flex-wrap justify-content-between align-items-center flex-1 gap-2\"\n >\n <div class=\"flex gap-2\">\n <spiderly-button\n [disabled]=\"disabled\"\n (onClick)=\"choose($event, chooseCallback)\"\n icon=\"pi pi-upload\"\n [rounded]=\"true\"\n [outlined]=\"true\"\n />\n </div>\n </div>\n </ng-template>\n <ng-template\n pTemplate=\"content\"\n let-files\n let-removeFileCallback=\"removeFileCallback\"\n >\n <div *ngIf=\"files.length > 0\">\n <div class=\"flex justify-content-center p-0 gap-5\">\n <div\n *ngFor=\"let file of files; let index = index\"\n class=\"card m-0 px-3 py-3 flex flex-column align-items-center gap-3\"\n style=\"justify-content: center; overflow: hidden\"\n >\n <div *ngIf=\"
|
|
1361
|
+
], template: "<ng-container *transloco=\"let t\">\n <div style=\"display: flex; flex-direction: column; gap: 0.5rem; padding: 1px\">\n <div *ngIf=\"getTranslatedLabel() != '' && getTranslatedLabel() != null\">\n <label>{{ getTranslatedLabel() }}</label>\n <!-- It's okay for this control, because for the custom uploads where we are not initializing the control from the backend, there is no need for formControl. -->\n <required *ngIf=\"control?.required || required\"></required>\n </div>\n\n <p-fileUpload\n [files]=\"files\"\n [disabled]=\"disabled\"\n [name]=\"control?.label ?? label\"\n [multiple]=\"multiple\"\n [accept]=\"acceptedFileTypesCommaSeparated\"\n [maxFileSize]=\"1000000\"\n (onSelect)=\"filesSelected($event)\"\n [class]=\"control?.invalid && control?.dirty ? 'control-error-border' : ''\"\n >\n <ng-template\n pTemplate=\"header\"\n let-files\n let-chooseCallback=\"chooseCallback\"\n let-clearCallback=\"clearCallback\"\n let-uploadCallback=\"uploadCallback\"\n >\n <div\n class=\"flex flex-wrap justify-content-between align-items-center flex-1 gap-2\"\n >\n <div class=\"flex gap-2\">\n <spiderly-button\n [disabled]=\"disabled\"\n (onClick)=\"choose($event, chooseCallback)\"\n icon=\"pi pi-upload\"\n [rounded]=\"true\"\n [outlined]=\"true\"\n />\n </div>\n </div>\n </ng-template>\n <ng-template\n pTemplate=\"content\"\n let-files\n let-removeFileCallback=\"removeFileCallback\"\n >\n <div *ngIf=\"files.length > 0\">\n <div class=\"flex justify-content-center p-0 gap-5\">\n <div\n *ngFor=\"let file of files; let index = index\"\n class=\"card m-0 px-3 py-3 flex flex-column align-items-center gap-3\"\n style=\"justify-content: center; overflow: hidden\"\n >\n <div *ngIf=\"isFileImageType(file.type)\" class=\"image-container\">\n <img role=\"presentation\" [src]=\"file.objectURL\" />\n </div>\n <div *ngIf=\"isExcelFileType(file.type)\" class=\"excel-container\">\n <div class=\"excel-details\">\n <i\n class=\"pi pi-file-excel\"\n style=\"color: green; margin-right: 4px\"\n ></i>\n <span class=\"file-name\">{{ file.name }}</span>\n </div>\n </div>\n <spiderly-button\n [disabled]=\"disabled\"\n icon=\"pi pi-times\"\n (onClick)=\"fileRemoved(removeFileCallback, index)\"\n [outlined]=\"true\"\n [rounded]=\"true\"\n severity=\"danger\"\n />\n </div>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"file\"> </ng-template>\n <ng-template pTemplate=\"empty\">\n <div class=\"flex align-items-center justify-content-center flex-column\">\n <i\n class=\"pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400 mt-3\"\n ></i>\n <p class=\"mt-4 mb-0\">{{ t(\"DragAndDropFilesHereToUpload\") }}</p>\n </div>\n </ng-template>\n </p-fileUpload>\n </div>\n</ng-container>\n" }]
|
|
1307
1362
|
}], ctorParameters: () => [{ type: i1.TranslocoService }, { type: SpiderlyMessageService }, { type: ValidatorAbstractService }], propDecorators: { onFileSelected: [{
|
|
1308
1363
|
type: Output
|
|
1309
1364
|
}], onFileRemoved: [{
|
|
@@ -1328,10 +1383,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
1328
1383
|
type: Input
|
|
1329
1384
|
}] } });
|
|
1330
1385
|
class SpiderlyFileSelectEvent extends BaseEntity {
|
|
1331
|
-
constructor({ file, formData, } = {}) {
|
|
1386
|
+
constructor({ file, formData, width, height, } = {}) {
|
|
1332
1387
|
super();
|
|
1333
1388
|
this.file = file;
|
|
1334
1389
|
this.formData = formData;
|
|
1390
|
+
this.width = width;
|
|
1391
|
+
this.height = height;
|
|
1335
1392
|
}
|
|
1336
1393
|
static { this.typeName = 'SpiderlyFileSelectEvent'; }
|
|
1337
1394
|
}
|
|
@@ -1548,12 +1605,12 @@ class UserRole extends BaseEntity {
|
|
|
1548
1605
|
}
|
|
1549
1606
|
class LoginVerificationToken extends BaseEntity {
|
|
1550
1607
|
static { this.typeName = 'LoginVerificationToken'; }
|
|
1551
|
-
constructor({ email, userId, browserId,
|
|
1608
|
+
constructor({ email, userId, browserId, expiresAt, } = {}) {
|
|
1552
1609
|
super();
|
|
1553
1610
|
this.email = email;
|
|
1554
1611
|
this.userId = userId;
|
|
1555
1612
|
this.browserId = browserId;
|
|
1556
|
-
this.
|
|
1613
|
+
this.expiresAt = expiresAt;
|
|
1557
1614
|
}
|
|
1558
1615
|
static { this.schema = {
|
|
1559
1616
|
email: {
|
|
@@ -1565,7 +1622,7 @@ class LoginVerificationToken extends BaseEntity {
|
|
|
1565
1622
|
browserId: {
|
|
1566
1623
|
type: 'string',
|
|
1567
1624
|
},
|
|
1568
|
-
|
|
1625
|
+
expiresAt: {
|
|
1569
1626
|
type: 'Date',
|
|
1570
1627
|
},
|
|
1571
1628
|
}; }
|
|
@@ -1622,21 +1679,8 @@ class SpiderlyError extends Error {
|
|
|
1622
1679
|
}
|
|
1623
1680
|
}
|
|
1624
1681
|
|
|
1625
|
-
class TranslateLabelsAbstractService {
|
|
1626
|
-
constructor() { }
|
|
1627
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: TranslateLabelsAbstractService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1628
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: TranslateLabelsAbstractService, providedIn: 'root' }); }
|
|
1629
|
-
}
|
|
1630
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: TranslateLabelsAbstractService, decorators: [{
|
|
1631
|
-
type: Injectable,
|
|
1632
|
-
args: [{
|
|
1633
|
-
providedIn: 'root',
|
|
1634
|
-
}]
|
|
1635
|
-
}], ctorParameters: () => [] });
|
|
1636
|
-
|
|
1637
1682
|
class BaseFormService {
|
|
1638
|
-
constructor(
|
|
1639
|
-
this.translateLabelsService = translateLabelsService;
|
|
1683
|
+
constructor(validatorService, messageService, translocoService) {
|
|
1640
1684
|
this.validatorService = validatorService;
|
|
1641
1685
|
this.messageService = messageService;
|
|
1642
1686
|
this.translocoService = translocoService;
|
|
@@ -1656,12 +1700,14 @@ class BaseFormService {
|
|
|
1656
1700
|
propSchema.type !== 'Namebook[]') {
|
|
1657
1701
|
if (existingControl instanceof SpiderlyFormArray) {
|
|
1658
1702
|
this.initFormArray(existingControl, propSchema.nestedConstructor, propInitialValue);
|
|
1703
|
+
this.validatorService.setFormArrayValidator(existingControl, targetClass.typeName);
|
|
1659
1704
|
}
|
|
1660
1705
|
else {
|
|
1661
1706
|
const control = new SpiderlyFormArray([], this.translocoService, this);
|
|
1662
1707
|
this.initFormArray(control, propSchema.nestedConstructor, propInitialValue);
|
|
1663
1708
|
control.label = formControlName;
|
|
1664
1709
|
control.labelForDisplay = this.getTranslatedLabel(formControlName);
|
|
1710
|
+
this.validatorService.setFormArrayValidator(control, targetClass.typeName);
|
|
1665
1711
|
formGroup.setControl(formControlName, control);
|
|
1666
1712
|
}
|
|
1667
1713
|
}
|
|
@@ -1681,6 +1727,9 @@ class BaseFormService {
|
|
|
1681
1727
|
if (formControlName === 'id' && !propInitialValue) {
|
|
1682
1728
|
propInitialValue = 0;
|
|
1683
1729
|
}
|
|
1730
|
+
if (propSchema.type.endsWith('[]') && propInitialValue == null) {
|
|
1731
|
+
propInitialValue = [];
|
|
1732
|
+
}
|
|
1684
1733
|
if (existingControl instanceof SpiderlyFormControl) {
|
|
1685
1734
|
existingControl.setValue(propInitialValue);
|
|
1686
1735
|
}
|
|
@@ -1755,7 +1804,7 @@ class BaseFormService {
|
|
|
1755
1804
|
else if (formControlName.endsWith('DisplayName')) {
|
|
1756
1805
|
formControlName = formControlName.replace('DisplayName', '');
|
|
1757
1806
|
}
|
|
1758
|
-
return this.
|
|
1807
|
+
return this.translocoService.translate(firstCharToUpper(formControlName));
|
|
1759
1808
|
}
|
|
1760
1809
|
addNewFormGroupToFormArray(formArray, targetClass, initialValues, index) {
|
|
1761
1810
|
let helperFormGroup = new SpiderlyFormGroup({});
|
|
@@ -1815,6 +1864,11 @@ class BaseFormService {
|
|
|
1815
1864
|
});
|
|
1816
1865
|
}
|
|
1817
1866
|
else if (control instanceof SpiderlyFormArray) {
|
|
1867
|
+
if (control.errors) {
|
|
1868
|
+
control.markAsDirty();
|
|
1869
|
+
this.messageService.warningMessage(control.errors['_']);
|
|
1870
|
+
invalid = true;
|
|
1871
|
+
}
|
|
1818
1872
|
control.controls.forEach((nestedControl) => {
|
|
1819
1873
|
if (!this.isControlValid(nestedControl)) {
|
|
1820
1874
|
invalid = true;
|
|
@@ -1826,7 +1880,7 @@ class BaseFormService {
|
|
|
1826
1880
|
}
|
|
1827
1881
|
return true;
|
|
1828
1882
|
}
|
|
1829
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: BaseFormService, deps: [{ token:
|
|
1883
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: BaseFormService, deps: [{ token: ValidatorAbstractService }, { token: SpiderlyMessageService }, { token: i1.TranslocoService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1830
1884
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: BaseFormService, providedIn: 'root' }); }
|
|
1831
1885
|
}
|
|
1832
1886
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: BaseFormService, decorators: [{
|
|
@@ -1834,7 +1888,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
1834
1888
|
args: [{
|
|
1835
1889
|
providedIn: 'root',
|
|
1836
1890
|
}]
|
|
1837
|
-
}], ctorParameters: () => [{ type:
|
|
1891
|
+
}], ctorParameters: () => [{ type: ValidatorAbstractService }, { type: SpiderlyMessageService }, { type: i1.TranslocoService }] });
|
|
1838
1892
|
|
|
1839
1893
|
class BaseFormCopy {
|
|
1840
1894
|
constructor(differs, http, messageService, changeDetectorRef, router, route, translocoService, baseFormService) {
|
|
@@ -1846,28 +1900,81 @@ class BaseFormCopy {
|
|
|
1846
1900
|
this.route = route;
|
|
1847
1901
|
this.translocoService = translocoService;
|
|
1848
1902
|
this.baseFormService = baseFormService;
|
|
1903
|
+
/**
|
|
1904
|
+
* The root form group that holds all form controls, typed to `TSaveBody`.
|
|
1905
|
+
* Assign `saveObservableMethod` on it to define the HTTP call used for saving.
|
|
1906
|
+
* The form controls are built automatically from the `TSaveBody` schema when you call
|
|
1907
|
+
* `baseFormService.initFormGroup(this.parentFormGroup, saveBodyClass, saveBody)`.
|
|
1908
|
+
*
|
|
1909
|
+
* @example
|
|
1910
|
+
* ```ts
|
|
1911
|
+
* this.parentFormGroup.saveObservableMethod = this.apiService.saveProduct;
|
|
1912
|
+
*
|
|
1913
|
+
* this.baseFormService.initFormGroup(
|
|
1914
|
+
* this.parentFormGroup,
|
|
1915
|
+
* ProductSaveBody,
|
|
1916
|
+
* saveBody,
|
|
1917
|
+
* );
|
|
1918
|
+
* ```
|
|
1919
|
+
*/
|
|
1849
1920
|
this.parentFormGroup = new SpiderlyFormGroup({});
|
|
1921
|
+
/**
|
|
1922
|
+
* The toast message displayed after a successful save.
|
|
1923
|
+
* Override this to customize the success notification text for a specific entity.
|
|
1924
|
+
* If you want to change the message for all entities, update the `SuccessfulSaveToastDescription` key
|
|
1925
|
+
* in your translation JSON file instead.
|
|
1926
|
+
*
|
|
1927
|
+
* @example
|
|
1928
|
+
* ```ts
|
|
1929
|
+
* this.successfulSaveToastDescription = 'Product saved successfully!';
|
|
1930
|
+
* ```
|
|
1931
|
+
*/
|
|
1850
1932
|
this.successfulSaveToastDescription = this.translocoService.translate('SuccessfulSaveToastDescription');
|
|
1851
1933
|
//#region Model
|
|
1934
|
+
/**
|
|
1935
|
+
* Executes the save flow for the form. The execution order is:
|
|
1936
|
+
* 1. Builds the save body from the form's raw value.
|
|
1937
|
+
* 2. Calls {@link onBeforeSave} — use this to modify the save body before validation.
|
|
1938
|
+
* 3. Validates the form. If invalid, shows an error message and stops.
|
|
1939
|
+
* 4. Sends the save HTTP request via `saveObservableMethod`.
|
|
1940
|
+
* 5. Calls {@link onAfterSaveRequest} — fires immediately after the request is sent, before the response arrives.
|
|
1941
|
+
* 6. On successful response: shows a success toast, reroutes, and calls {@link onAfterSave}. The form is re-initialized only when `rerouteToParentSlugAfterSave` is `false`.
|
|
1942
|
+
*
|
|
1943
|
+
* @param rerouteToParentSlugAfterSave - When `true` (default), navigates to the parent URL after save. When `false`, re-initializes the form and navigates to the saved object's URL.
|
|
1944
|
+
*
|
|
1945
|
+
* @example
|
|
1946
|
+
* ```html
|
|
1947
|
+
* <button (click)="onSave()">Save</button>
|
|
1948
|
+
* ```
|
|
1949
|
+
*
|
|
1950
|
+
* @example
|
|
1951
|
+
* ```html
|
|
1952
|
+
* <!-- Save and stay on the saved object's page -->
|
|
1953
|
+
* <button (click)="onSave(false)">Save and stay</button>
|
|
1954
|
+
* ```
|
|
1955
|
+
*/
|
|
1852
1956
|
// onSave method is here only because of the hooks, we should move everything except them to the BaseFromService
|
|
1853
|
-
this.onSave = (
|
|
1957
|
+
this.onSave = (rerouteToParentSlugAfterSave = true) => {
|
|
1854
1958
|
if (!this.saveBodyClass)
|
|
1855
1959
|
throw new SpiderlyError('You did not initialize saveBodyClass');
|
|
1856
1960
|
if (!this.mainUIFormClass)
|
|
1857
1961
|
throw new SpiderlyError('You did not initialize mainUIFormClass');
|
|
1858
|
-
|
|
1859
|
-
this.onBeforeSave(
|
|
1860
|
-
this.saveBody = this.saveBody ?? this.parentFormGroup.getRawValue();
|
|
1962
|
+
let saveBody = this.parentFormGroup.getRawValue();
|
|
1963
|
+
this.onBeforeSave(saveBody);
|
|
1861
1964
|
const isValid = this.baseFormService.isControlValid(this.parentFormGroup);
|
|
1862
1965
|
if (isValid) {
|
|
1863
1966
|
this.parentFormGroup
|
|
1864
|
-
.saveObservableMethod(
|
|
1967
|
+
.saveObservableMethod(saveBody)
|
|
1865
1968
|
.subscribe((res) => {
|
|
1866
1969
|
this.messageService.successMessage(this.successfulSaveToastDescription);
|
|
1867
|
-
|
|
1868
|
-
|
|
1970
|
+
if (rerouteToParentSlugAfterSave) {
|
|
1971
|
+
this.rerouteToSavedObject(undefined);
|
|
1972
|
+
}
|
|
1973
|
+
else {
|
|
1974
|
+
saveBody = this.baseFormService.mapMainUIFormToSaveBody(this.mainUIFormClass, res);
|
|
1975
|
+
this.baseFormService.initFormGroup(this.parentFormGroup, this.saveBodyClass, saveBody);
|
|
1869
1976
|
const saveBodyMainDTOKey = this.baseFormService.getSaveBodyMainDTOKey(this.saveBodyClass);
|
|
1870
|
-
const savedObjectId =
|
|
1977
|
+
const savedObjectId = saveBody[saveBodyMainDTOKey]?.id;
|
|
1871
1978
|
this.rerouteToSavedObject(savedObjectId); // You always need to have id, because of id == 0 and version change
|
|
1872
1979
|
}
|
|
1873
1980
|
this.onAfterSave();
|
|
@@ -1878,6 +1985,21 @@ class BaseFormCopy {
|
|
|
1878
1985
|
this.baseFormService.showInvalidFieldsMessage();
|
|
1879
1986
|
}
|
|
1880
1987
|
};
|
|
1988
|
+
/**
|
|
1989
|
+
* Handles navigation after a successful save.
|
|
1990
|
+
* Override this to customize the post-save navigation behavior.
|
|
1991
|
+
* By default, navigates to the parent URL when `rerouteId` is not provided, or to the saved object's URL otherwise.
|
|
1992
|
+
*
|
|
1993
|
+
* @param rerouteId - The ID of the saved object, used to build the target URL. When not provided, navigates to the parent URL.
|
|
1994
|
+
*
|
|
1995
|
+
* @example
|
|
1996
|
+
* ```ts
|
|
1997
|
+
* // Override to navigate to a custom route after save
|
|
1998
|
+
* rerouteToSavedObject = (rerouteId: number | string): void => {
|
|
1999
|
+
* this.router.navigateByUrl(`/products/${rerouteId}/details`);
|
|
2000
|
+
* };
|
|
2001
|
+
* ```
|
|
2002
|
+
*/
|
|
1881
2003
|
this.rerouteToSavedObject = (rerouteId) => {
|
|
1882
2004
|
if (rerouteId == null) {
|
|
1883
2005
|
const currentUrl = this.router.url;
|
|
@@ -1890,8 +2012,43 @@ class BaseFormCopy {
|
|
|
1890
2012
|
const newUrl = segments.join('/');
|
|
1891
2013
|
this.router.navigateByUrl(newUrl);
|
|
1892
2014
|
};
|
|
2015
|
+
/**
|
|
2016
|
+
* Hook that runs **before** form validation and the save request.
|
|
2017
|
+
* Use this to modify the save body or perform any pre-save logic (e.g., transforming data, setting computed fields).
|
|
2018
|
+
*
|
|
2019
|
+
* @param saveBody - The current save body built from the form's raw value. Mutate it directly to change what gets sent to the server.
|
|
2020
|
+
*
|
|
2021
|
+
* @example
|
|
2022
|
+
* ```ts
|
|
2023
|
+
* onBeforeSave = (saveBody?: ProductSaveBody) => {
|
|
2024
|
+
* saveBody.productDTO.fullName = saveBody.productDTO.firstName + ' ' + saveBody.productDTO.lastName;
|
|
2025
|
+
* };
|
|
2026
|
+
* ```
|
|
2027
|
+
*/
|
|
1893
2028
|
this.onBeforeSave = (saveBody) => { };
|
|
2029
|
+
/**
|
|
2030
|
+
* Hook that runs **after** a successful save response is received.
|
|
2031
|
+
* Use this for post-save side effects (e.g., refreshing related data, showing additional notifications).
|
|
2032
|
+
*
|
|
2033
|
+
* @example
|
|
2034
|
+
* ```ts
|
|
2035
|
+
* onAfterSave = () => {
|
|
2036
|
+
* this.loadRelatedProducts();
|
|
2037
|
+
* };
|
|
2038
|
+
* ```
|
|
2039
|
+
*/
|
|
1894
2040
|
this.onAfterSave = () => { };
|
|
2041
|
+
/**
|
|
2042
|
+
* Hook that runs immediately **after** the save HTTP request is sent, but **before** the response arrives.
|
|
2043
|
+
* Use this for side effects that should happen as soon as the request is dispatched (e.g., disabling UI elements, starting a loading indicator).
|
|
2044
|
+
*
|
|
2045
|
+
* @example
|
|
2046
|
+
* ```ts
|
|
2047
|
+
* onAfterSaveRequest = () => {
|
|
2048
|
+
* this.isSaving = true;
|
|
2049
|
+
* };
|
|
2050
|
+
* ```
|
|
2051
|
+
*/
|
|
1895
2052
|
this.onAfterSaveRequest = () => { };
|
|
1896
2053
|
}
|
|
1897
2054
|
ngOnInit() { }
|
|
@@ -1961,6 +2118,7 @@ class ConfigServiceBase {
|
|
|
1961
2118
|
constructor() {
|
|
1962
2119
|
this.production = false;
|
|
1963
2120
|
this.frontendUrl = 'http://localhost:4200';
|
|
2121
|
+
this.showGoogleAuth = false;
|
|
1964
2122
|
this.companyName = 'Company Name';
|
|
1965
2123
|
this.primaryColor = '#111b2c';
|
|
1966
2124
|
/* URLs */
|
|
@@ -2254,7 +2412,6 @@ class AuthComponent {
|
|
|
2254
2412
|
this.authService = authService;
|
|
2255
2413
|
this.initCompanyAuthDialogDetailsSubscription = null;
|
|
2256
2414
|
this.onCompanyNameChange = new EventEmitter();
|
|
2257
|
-
this.showGoogleAuth = false;
|
|
2258
2415
|
}
|
|
2259
2416
|
ngOnInit() {
|
|
2260
2417
|
this.initCompanyDetails();
|
|
@@ -2279,15 +2436,13 @@ class AuthComponent {
|
|
|
2279
2436
|
}
|
|
2280
2437
|
}
|
|
2281
2438
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: AuthComponent, deps: [{ token: ConfigServiceBase }, { token: AuthServiceBase }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2282
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.13", type: AuthComponent, isStandalone: true, selector: "auth",
|
|
2439
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.13", type: AuthComponent, isStandalone: true, selector: "auth", outputs: { onCompanyNameChange: "onCompanyNameChange" }, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div class=\"flex min-h-screen overflow-hidden\" style=\"padding: 20px\">\n <div class=\"flex flex-column w-full\">\n <div\n class=\"w-full sm:w-30rem\"\n style=\"\n margin: auto;\n border-radius: 50px;\n padding: 0.3rem;\n background: linear-gradient(\n 180deg,\n var(--p-primary-color) 10%,\n rgba(33, 150, 243, 0) 30%\n );\n \"\n >\n <div class=\"surface-card py-6 px-5 sm:px-6\" style=\"border-radius: 45px\">\n <div class=\"text-center\" style=\"margin-bottom: 38px\">\n <img\n *ngIf=\"image != null\"\n [src]=\"image\"\n alt=\"{{ companyName }} Logo\"\n title=\"{{ companyName }} Logo\"\n height=\"60\"\n />\n <i\n *ngIf=\"image == null\"\n class=\"pi pi-spin pi-spinner primary-color\"\n style=\"font-size: 2rem\"\n ></i>\n </div>\n\n <ng-content></ng-content>\n\n <div *ngIf=\"config.showGoogleAuth\">\n <div\n style=\"\n display: flex;\n align-items: center;\n gap: 7px;\n justify-content: center;\n margin-bottom: 16px;\n \"\n >\n <div class=\"separator\"></div>\n <div>{{ t(\"or\") }}</div>\n <div class=\"separator\"></div>\n </div>\n <div>\n <!-- https://code-maze.com/how-to-sign-in-with-google-angular-aspnet-webapi/ -->\n <google-button\n (loginWithGoogle)=\"onGoogleSignIn($event)\"\n [label]=\"t('ContinueWithGoogle')\"\n ></google-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: GoogleButtonComponent, selector: "google-button", inputs: ["label"], outputs: ["loginWithGoogle"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] }); }
|
|
2283
2440
|
}
|
|
2284
2441
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: AuthComponent, decorators: [{
|
|
2285
2442
|
type: Component,
|
|
2286
|
-
args: [{ selector: 'auth', imports: [CommonModule, GoogleButtonComponent, TranslocoDirective], template: "<ng-container *transloco=\"let t\">\n <div class=\"flex min-h-screen overflow-hidden\" style=\"padding: 20px\">\n <div class=\"flex flex-column w-full\">\n <div\n class=\"w-full sm:w-30rem\"\n style=\"\n margin: auto;\n border-radius: 50px;\n padding: 0.3rem;\n background: linear-gradient(\n 180deg,\n var(--p-primary-color) 10%,\n rgba(33, 150, 243, 0) 30%\n );\n \"\n >\n <div class=\"surface-card py-6 px-5 sm:px-6\" style=\"border-radius: 45px\">\n <div class=\"text-center\" style=\"margin-bottom: 38px\">\n <img\n *ngIf=\"image != null\"\n [src]=\"image\"\n alt=\"{{ companyName }} Logo\"\n title=\"{{ companyName }} Logo\"\n height=\"60\"\n />\n <i\n *ngIf=\"image == null\"\n class=\"pi pi-spin pi-spinner primary-color\"\n style=\"font-size: 2rem\"\n ></i>\n </div>\n\n <ng-content></ng-content>\n\n <div *ngIf=\"showGoogleAuth\">\n <div\n style=\"\n display: flex;\n align-items: center;\n gap: 7px;\n justify-content: center;\n margin-bottom: 16px;\n \"\n >\n <div class=\"separator\"></div>\n <div>{{ t(\"or\") }}</div>\n <div class=\"separator\"></div>\n </div>\n <div>\n <!-- https://code-maze.com/how-to-sign-in-with-google-angular-aspnet-webapi/ -->\n <google-button\n (loginWithGoogle)=\"onGoogleSignIn($event)\"\n [label]=\"t('ContinueWithGoogle')\"\n ></google-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-container>\n" }]
|
|
2443
|
+
args: [{ selector: 'auth', imports: [CommonModule, GoogleButtonComponent, TranslocoDirective], template: "<ng-container *transloco=\"let t\">\n <div class=\"flex min-h-screen overflow-hidden\" style=\"padding: 20px\">\n <div class=\"flex flex-column w-full\">\n <div\n class=\"w-full sm:w-30rem\"\n style=\"\n margin: auto;\n border-radius: 50px;\n padding: 0.3rem;\n background: linear-gradient(\n 180deg,\n var(--p-primary-color) 10%,\n rgba(33, 150, 243, 0) 30%\n );\n \"\n >\n <div class=\"surface-card py-6 px-5 sm:px-6\" style=\"border-radius: 45px\">\n <div class=\"text-center\" style=\"margin-bottom: 38px\">\n <img\n *ngIf=\"image != null\"\n [src]=\"image\"\n alt=\"{{ companyName }} Logo\"\n title=\"{{ companyName }} Logo\"\n height=\"60\"\n />\n <i\n *ngIf=\"image == null\"\n class=\"pi pi-spin pi-spinner primary-color\"\n style=\"font-size: 2rem\"\n ></i>\n </div>\n\n <ng-content></ng-content>\n\n <div *ngIf=\"config.showGoogleAuth\">\n <div\n style=\"\n display: flex;\n align-items: center;\n gap: 7px;\n justify-content: center;\n margin-bottom: 16px;\n \"\n >\n <div class=\"separator\"></div>\n <div>{{ t(\"or\") }}</div>\n <div class=\"separator\"></div>\n </div>\n <div>\n <!-- https://code-maze.com/how-to-sign-in-with-google-angular-aspnet-webapi/ -->\n <google-button\n (loginWithGoogle)=\"onGoogleSignIn($event)\"\n [label]=\"t('ContinueWithGoogle')\"\n ></google-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-container>\n" }]
|
|
2287
2444
|
}], ctorParameters: () => [{ type: ConfigServiceBase }, { type: AuthServiceBase }], propDecorators: { onCompanyNameChange: [{
|
|
2288
2445
|
type: Output
|
|
2289
|
-
}], showGoogleAuth: [{
|
|
2290
|
-
type: Input
|
|
2291
2446
|
}] } });
|
|
2292
2447
|
|
|
2293
2448
|
class PanelBodyComponent {
|
|
@@ -2580,7 +2735,7 @@ class LoginComponent extends BaseFormCopy {
|
|
|
2580
2735
|
});
|
|
2581
2736
|
}
|
|
2582
2737
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: LoginComponent, deps: [{ token: i0.KeyValueDiffers }, { token: i1$3.HttpClient }, { token: SpiderlyMessageService }, { token: i0.ChangeDetectorRef }, { token: i3$2.Router }, { token: i3$2.ActivatedRoute }, { token: i1.TranslocoService }, { token: BaseFormService }, { token: AuthServiceBase }, { token: ConfigServiceBase }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2583
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.13", type: LoginComponent, isStandalone: true, selector: "app-login", usesInheritance: true, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n @if (loginFormGroup != null) {\n @if (showEmailSentDialog == false) {\n <auth (onCompanyNameChange)=\"companyNameChange($event)\">\n <!-- We are not loading anything from the server here so we don't need defer block -->\n <form [formGroup]=\"loginFormGroup\" style=\"margin-bottom: 16px\">\n <div class=\"col-12\" style=\"padding-left: 0; padding-right: 0\">\n <spiderly-textbox\n [control]=\"loginFormGroup.getControl('email')\"\n ></spiderly-textbox>\n </div>\n\n <div class=\"mb-4 gap-5\">\n <div class=\"text-center\" style=\"font-size: smaller\">\n {{ t(\"AgreementsOnRegister\") }}\n <b\n routerLink=\"/user-agreement\"\n class=\"primary-color cursor-pointer\"\n >{{ t(\"UserAgreement\") }}</b\n >\n {{ t(\"and\") }}\n <b\n routerLink=\"/privacy-policy\"\n class=\"primary-color cursor-pointer\"\n >{{ t(\"PrivacyPolicy\") }}</b\n >.\n </div>\n </div>\n\n <div style=\"display: flex; flex-direction: column; gap: 16px\">\n <spiderly-button\n [label]=\"t('Login')\"\n (onClick)=\"sendLoginVerificationEmail()\"\n [outlined]=\"true\"\n [style]=\"{ width: '100%' }\"\n type=\"submit\"\n ></spiderly-button>\n </div>\n </form>\n </auth>\n } @else {\n <login-verification\n [email]=\"loginFormGroup.controls.email.getRawValue()\"\n ></login-verification>\n }\n } @else {\n <!-- TODO: Add skeleton -->\n }\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: AuthComponent, selector: "auth",
|
|
2738
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.13", type: LoginComponent, isStandalone: true, selector: "app-login", usesInheritance: true, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n @if (loginFormGroup != null) {\n @if (showEmailSentDialog == false) {\n <auth (onCompanyNameChange)=\"companyNameChange($event)\">\n <!-- We are not loading anything from the server here so we don't need defer block -->\n <form [formGroup]=\"loginFormGroup\" style=\"margin-bottom: 16px\">\n <div class=\"col-12\" style=\"padding-left: 0; padding-right: 0\">\n <spiderly-textbox\n [control]=\"loginFormGroup.getControl('email')\"\n ></spiderly-textbox>\n </div>\n\n <div class=\"mb-4 gap-5\">\n <div class=\"text-center\" style=\"font-size: smaller\">\n {{ t(\"AgreementsOnRegister\") }}\n <b\n routerLink=\"/user-agreement\"\n class=\"primary-color cursor-pointer\"\n >{{ t(\"UserAgreement\") }}</b\n >\n {{ t(\"and\") }}\n <b\n routerLink=\"/privacy-policy\"\n class=\"primary-color cursor-pointer\"\n >{{ t(\"PrivacyPolicy\") }}</b\n >.\n </div>\n </div>\n\n <div style=\"display: flex; flex-direction: column; gap: 16px\">\n <spiderly-button\n [label]=\"t('Login')\"\n (onClick)=\"sendLoginVerificationEmail()\"\n [outlined]=\"true\"\n [style]=\"{ width: '100%' }\"\n type=\"submit\"\n ></spiderly-button>\n </div>\n </form>\n </auth>\n } @else {\n <login-verification\n [email]=\"loginFormGroup.controls.email.getRawValue()\"\n ></login-verification>\n }\n } @else {\n <!-- TODO: Add skeleton -->\n }\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: AuthComponent, selector: "auth", outputs: ["onCompanyNameChange"] }, { kind: "ngmodule", type: SpiderlyControlsModule }, { kind: "component", type: SpiderlyTextboxComponent, selector: "spiderly-textbox", inputs: ["showButton", "buttonIcon"], outputs: ["onButtonClick"] }, { kind: "component", type: SpiderlyButtonComponent, selector: "spiderly-button", inputs: ["type"] }, { kind: "component", type: LoginVerificationComponent, selector: "login-verification", inputs: ["email", "userId"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }] }); }
|
|
2584
2739
|
}
|
|
2585
2740
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: LoginComponent, decorators: [{
|
|
2586
2741
|
type: Component,
|
|
@@ -4379,21 +4534,6 @@ class LazyLoadSelectedIdsResult extends BaseEntity {
|
|
|
4379
4534
|
class MenuChangeEvent {
|
|
4380
4535
|
}
|
|
4381
4536
|
|
|
4382
|
-
class MimeTypes {
|
|
4383
|
-
constructor(value) {
|
|
4384
|
-
this.value = value;
|
|
4385
|
-
}
|
|
4386
|
-
static { this.Pdf = new MimeTypes('application/pdf'); }
|
|
4387
|
-
static { this.Zip = new MimeTypes('application/zip'); }
|
|
4388
|
-
static { this.Jpeg = new MimeTypes('image/jpeg'); }
|
|
4389
|
-
static { this.Png = new MimeTypes('image/png'); }
|
|
4390
|
-
static { this.Svg = new MimeTypes('image/svg'); }
|
|
4391
|
-
static { this.Webp = new MimeTypes('image/webp'); }
|
|
4392
|
-
toString() {
|
|
4393
|
-
return this.value;
|
|
4394
|
-
}
|
|
4395
|
-
}
|
|
4396
|
-
|
|
4397
4537
|
class Namebook extends BaseEntity {
|
|
4398
4538
|
constructor({ id, displayName, } = {}) {
|
|
4399
4539
|
super();
|
|
@@ -4731,5 +4871,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
4731
4871
|
* Generated bundle index. Do not edit.
|
|
4732
4872
|
*/
|
|
4733
4873
|
|
|
4734
|
-
export { Action, AllClickEvent, ApiSecurityService, AppSidebarComponent, AuthGuard, AuthResult, AuthServiceBase, BaseAutocompleteControl, BaseControl, BaseDropdownControl, BaseEntity, BaseFormCopy, BaseFormService, CardSkeletonComponent, Codebook, Column, ConfigServiceBase, ExternalProvider, Filter, FilterRule, FilterSortMeta, FooterComponent, GoogleButtonComponent, IndexCardComponent, InfoCardComponent, InitCompanyAuthDialogDetails, InitTopBarData, IsAuthorizedForSaveEvent, LastMenuIconIndexClicked, LayoutServiceBase, LazyLoadSelectedIdsResult, Login, LoginComponent, LoginVerificationComponent, LoginVerificationToken, MatchModeCodes, MenuChangeEvent, MenuitemComponent,
|
|
4874
|
+
export { Action, AllClickEvent, ApiSecurityService, AppSidebarComponent, AuthGuard, AuthResult, AuthServiceBase, BaseAutocompleteControl, BaseControl, BaseDropdownControl, BaseEntity, BaseFormCopy, BaseFormService, CardSkeletonComponent, Codebook, Column, ConfigServiceBase, ExternalProvider, Filter, FilterRule, FilterSortMeta, FooterComponent, GoogleButtonComponent, IndexCardComponent, InfoCardComponent, InitCompanyAuthDialogDetails, InitTopBarData, IsAuthorizedForSaveEvent, LastMenuIconIndexClicked, LayoutServiceBase, LazyLoadSelectedIdsResult, Login, LoginComponent, LoginVerificationComponent, LoginVerificationToken, MatchModeCodes, MenuChangeEvent, MenuitemComponent, Namebook, NotAuthGuard, NotFoundComponent, PROPS_KEY, PaginatedResult, PanelBodyComponent, PanelFooterComponent, PanelHeaderComponent, PrimengOption, ProfileAvatarComponent, ReflectProp, RefreshTokenRequest, RequiredComponent, RowClickEvent, SecurityPermissionCodes, SendLoginVerificationEmailResult, SideMenuTopBarComponent, SidebarMenuComponent, SimpleSaveResult, SpiderlyAutocompleteComponent, SpiderlyButtonBaseComponent, SpiderlyButtonComponent, SpiderlyCalendarComponent, SpiderlyCardComponent, SpiderlyCheckboxComponent, SpiderlyColorPickerComponent, SpiderlyControlsModule, SpiderlyDataTableComponent, SpiderlyDataViewComponent, SpiderlyDeleteConfirmationComponent, SpiderlyDropdownComponent, SpiderlyEditorComponent, SpiderlyErrorHandler, SpiderlyFileComponent, SpiderlyFileSelectEvent, SpiderlyFormArray, SpiderlyFormControl, SpiderlyFormGroup, SpiderlyLayoutComponent, SpiderlyMessageService, SpiderlyMultiAutocompleteComponent, SpiderlyMultiSelectComponent, SpiderlyNumberComponent, SpiderlyPanelComponent, SpiderlyPanelsModule, SpiderlyPasswordComponent, SpiderlyReturnButtonComponent, SpiderlySplitButtonComponent, SpiderlyTab, SpiderlyTemplateTypeDirective, SpiderlyTextareaComponent, SpiderlyTextboxComponent, SpiderlyTranslocoLoader, TopBarComponent, UserBase, UserRole, ValidatorAbstractService, VerificationTokenRequest, VerificationTypeCodes, VerificationWrapperComponent, adjustColor, authInitializer, capitalizeFirstChar, createFakeGoogleWrapper, deleteAction, exportListToExcel, firstCharToUpper, getFileNameFromContentDisposition, getHtmlImgDisplayString64, getImageDimensions, getMimeTypeForFileName, getMonth, getParentUrl, getPrimengAutocompleteCodebookOptions, getPrimengAutocompleteNamebookOptions, getPrimengDropdownCodebookOptions, getPrimengDropdownNamebookOptions, httpLoadingInterceptor, isExcelFileType, isFileImageType, isNullOrEmpty, jsonHttpInterceptor, jwtInterceptor, kebabToTitleCase, nameOf, nameof, primitiveArrayTypes, pushAction, selectedTab, singleOrDefault, splitPascalCase, toCommaSeparatedString, unauthorizedInterceptor, validatePrecisionScale };
|
|
4735
4875
|
//# sourceMappingURL=spiderly.mjs.map
|