TS migration

This commit is contained in:
Yurii
2026-04-30 14:15:05 +03:00
parent 1f4287c844
commit 11bd0d9d67
10 changed files with 186 additions and 148 deletions

View File

@@ -279,7 +279,7 @@ export default class Model<T extends Record<string, unknown> = Record<string, an
set(
attribute: keyof T,
value: any,
options?: {silent: boolean} & Record<string, any>,
options?: {silent?: boolean} & Record<string, any>,
): this {
if (attribute == null) {

View File

@@ -28,7 +28,12 @@
/** @module views/fields/array */
import BaseFieldView, {BaseOptions as BaseOptions, BaseParams as BaseParams, BaseViewSchema} from 'views/fields/base';
import BaseFieldView, {
BaseOptions as BaseOptions,
BaseParams as BaseParams,
BaseViewSchema,
FieldValidator,
} from 'views/fields/base';
import RegExpPattern from 'helpers/reg-exp-pattern';
import MultiSelect from 'ui/multi-select';
import ModalView, {ModalOptions} from 'views/modal';
@@ -163,7 +168,7 @@ class ArrayFieldView<
protected maxItemLength: number | null = null
protected validations = ['required', 'maxCount']
protected validations: (FieldValidator | string)[] = ['required', 'maxCount']
protected readonly MAX_ITEM_LENGTH = 100

View File

@@ -99,6 +99,8 @@ export interface BaseViewSchema {
model: Model;
}
export type FieldValidator = () => boolean;
type Mode = 'list' | 'listLink' | 'detail' | 'edit' | 'search';
/**
@@ -182,7 +184,7 @@ export default class BaseFieldView<
*
* Functions are supported as of v8.3.
*/
protected validations: Array<(() => boolean) | string> = ['required']
protected validations: (FieldValidator | string)[] = ['required']
/**
* List mode.

View File

@@ -1,3 +1,5 @@
// noinspection JSUnusedLocalSymbols
/************************************************************************
* This file is part of EspoCRM.
*
@@ -30,85 +32,111 @@
import FloatFieldView from 'views/fields/float';
import Select from 'ui/select';
import {BaseOptions, BaseParams, BaseViewSchema, FieldValidator} from 'views/fields/base';
/**
* Parameters.
*/
export interface CurrencyParams extends BaseParams {
/**
* A min value.
*/
min?: number;
/**
* A max value.
*/
max?: number;
/**
* Required.
*/
required?: boolean;
/**
* Disable formatting.
*/
disableFormatting?: boolean;
/**
* Decimal places.
*
* @todo ?
*/
decimalPlaces?: number | null;
/**
* onlyDefaultCurrency
*/
onlyDefaultCurrency?: boolean
/**
* Stored as decimal.
*/
decimal?: boolean
/**
* Scale (for decimal).
*/
scale?: number
}
/**
* Options.
*/
export interface CurrencyOptions extends BaseOptions {
/**
* Hide currency.
*/
hideCurrency?: boolean;
}
/**
* A currency field.
*
* @extends IntFieldView<module:views/fields/currency~params>
*/
class CurrencyFieldView extends FloatFieldView {
class CurrencyFieldView<
S extends BaseViewSchema = BaseViewSchema,
O extends CurrencyOptions = CurrencyOptions,
P extends CurrencyParams = CurrencyParams,
> extends FloatFieldView<S, O, P> {
/**
* @typedef {Object} module:views/fields/currency~options
* @property {
* module:views/fields/currency~params &
* module:views/fields/base~params &
* Record
* } [params] Parameters.
*/
readonly type: string = 'currency'
/**
* @typedef {Object} module:views/fields/currency~params
* @property {number} [min] A max value.
* @property {number} [max] A max value.
* @property {boolean} [required] Required.
* @property {boolean} [disableFormatting] Disable formatting.
* @property {number|null} [decimalPlaces] A number of decimal places. @todo
* @property {boolean} [onlyDefaultCurrency] Only the default currency.
* @property {boolean} [decimal] Stored as decimal.
* @property {number} [scale] Scale (for decimal).
*/
protected editTemplate = 'fields/currency/edit'
protected detailTemplate = 'fields/currency/detail'
protected listTemplate = 'fields/currency/list'
/**
* @param {
* module:views/fields/currency~options &
* module:views/fields/base~options
* } options Options.
*/
constructor(options) {
super(options);
}
type = 'currency'
editTemplate = 'fields/currency/edit'
detailTemplate = 'fields/currency/detail'
// noinspection JSUnusedGlobalSymbols
detailTemplate1 = 'fields/currency/detail-1'
protected detailTemplate1 = 'fields/currency/detail-1'
// noinspection JSUnusedGlobalSymbols
detailTemplate2 = 'fields/currency/detail-2'
protected detailTemplate2 = 'fields/currency/detail-2'
// noinspection JSUnusedGlobalSymbols
detailTemplate3 = 'fields/currency/detail-3'
listTemplate = 'fields/currency/list'
// noinspection JSUnusedGlobalSymbols
listTemplate1 = 'fields/currency/list-1'
// noinspection JSUnusedGlobalSymbols
listTemplate2 = 'fields/currency/list-2'
// noinspection JSUnusedGlobalSymbols
listTemplate3 = 'fields/currency/list-3'
detailTemplateNoCurrency = 'fields/currency/detail-no-currency'
protected detailTemplate3 = 'fields/currency/detail-3'
maxDecimalPlaces = 3
// noinspection JSUnusedGlobalSymbols
protected listTemplate1 = 'fields/currency/list-1'
// noinspection JSUnusedGlobalSymbols
protected listTemplate2 = 'fields/currency/list-2'
// noinspection JSUnusedGlobalSymbols
protected listTemplate3 = 'fields/currency/list-3'
/**
* @inheritDoc
* @type {Array<(function (): boolean)|string>}
*/
validations = [
protected detailTemplateNoCurrency = 'fields/currency/detail-no-currency'
protected maxDecimalPlaces: number = 3
protected validations: (FieldValidator | string)[] = [
'required',
'number',
'range',
]
/**
* @protected
* @type {string}
* @since 9.2.6
*/
currencyAttribute
protected currencyAttribute: string
/** @inheritDoc */
data() {
protected currencyFieldName: string
protected isSingleCurrency: boolean
protected defaultCurrency: string
protected currencyList: string[]
protected decimalPlaces: number
private $currency: JQuery
protected data() {
const currencyValue = this.model.get(this.currencyFieldName) ||
this.getPreferences().get('defaultCurrency') ||
this.getConfig().get('defaultCurrency');
@@ -126,8 +154,7 @@ class CurrencyFieldView extends FloatFieldView {
};
}
/** @inheritDoc */
setup() {
protected setup() {
super.setup();
this.currencyFieldName = this.currencyAttribute ?? this.name + 'Currency';
@@ -141,7 +168,7 @@ class CurrencyFieldView extends FloatFieldView {
this.isSingleCurrency = this.currencyList.length <= 1;
const currencyValue = this.currencyValue = this.model.get(this.currencyFieldName) ||
const currencyValue = this.model.get(this.currencyFieldName) ||
this.defaultCurrency;
if (!this.currencyList.includes(currencyValue)) {
@@ -150,8 +177,7 @@ class CurrencyFieldView extends FloatFieldView {
}
}
/** @inheritDoc */
setupAutoNumericOptions() {
protected setupAutoNumericOptions() {
this.autoNumericOptions = {
digitGroupSeparator: this.thousandSeparator || '',
decimalCharacter: this.decimalMark,
@@ -160,6 +186,7 @@ class CurrencyFieldView extends FloatFieldView {
decimalPlaces: this.decimalPlaces,
allowDecimalPadding: true,
showWarnings: false,
// @ts-ignore
formulaMode: true,
};
@@ -170,18 +197,17 @@ class CurrencyFieldView extends FloatFieldView {
}
}
getCurrencyFormat() {
protected getCurrencyFormat(): number {
return this.getConfig().get('currencyFormat') || 1;
}
_getTemplateName() {
if (this.mode === this.MODE_DETAIL || this.mode === this.MODE_LIST) {
let prop;
let prop: string;
if (this.mode === this.MODE_LIST) {
prop = 'listTemplate' + this.getCurrencyFormat().toString();
}
else {
} else {
prop = 'detailTemplate' + this.getCurrencyFormat().toString();
}
@@ -190,68 +216,66 @@ class CurrencyFieldView extends FloatFieldView {
}
if (prop in this) {
return this[prop];
return (this as any)[prop];
}
}
// @ts-ignore
return super._getTemplateName();
}
formatNumber(value) {
protected formatNumber(value: number | null): string | null {
return this.formatNumberDetail(value);
}
formatNumberDetail(value) {
if (value !== null) {
const currencyDecimalPlaces = this.decimalPlaces;
if (currencyDecimalPlaces === 0) {
value = Math.round(value);
}
else if (currencyDecimalPlaces) {
value = Math.round(
value * Math.pow(10, currencyDecimalPlaces)) / (Math.pow(10, currencyDecimalPlaces)
);
}
else {
value = Math.round(
value * Math.pow(10, this.maxDecimalPlaces)) / (Math.pow(10, this.maxDecimalPlaces)
);
}
const parts = value.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandSeparator);
if (currencyDecimalPlaces === 0) {
return parts[0];
}
else if (currencyDecimalPlaces) {
let decimalPartLength = 0;
if (parts.length > 1) {
decimalPartLength = parts[1].length;
} else {
parts[1] = '';
}
if (currencyDecimalPlaces && decimalPartLength < currencyDecimalPlaces) {
const limit = currencyDecimalPlaces - decimalPartLength;
for (let i = 0; i < limit; i++) {
parts[1] += '0';
}
}
}
return parts.join(this.decimalMark);
protected formatNumberDetail(value: number | null): string {
if (value === null) {
return '';
}
return '';
const currencyDecimalPlaces = this.decimalPlaces;
if (currencyDecimalPlaces === 0) {
value = Math.round(value);
} else if (currencyDecimalPlaces) {
value = Math.round(
value * Math.pow(10, currencyDecimalPlaces)) / (Math.pow(10, currencyDecimalPlaces)
);
} else {
value = Math.round(
value * Math.pow(10, this.maxDecimalPlaces)) / (Math.pow(10, this.maxDecimalPlaces)
);
}
const parts = value.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandSeparator);
if (currencyDecimalPlaces === 0) {
return parts[0];
} else if (currencyDecimalPlaces) {
let decimalPartLength = 0;
if (parts.length > 1) {
decimalPartLength = parts[1].length;
} else {
parts[1] = '';
}
if (currencyDecimalPlaces && decimalPartLength < currencyDecimalPlaces) {
const limit = currencyDecimalPlaces - decimalPartLength;
for (let i = 0; i < limit; i++) {
parts[1] += '0';
}
}
}
return parts.join(this.decimalMark);
}
parse(value) {
value = (value !== '') ? value : null;
protected parse(input: string): number | string | null {
let value = (input !== '') ? input : null;
if (value === null) {
return null;
@@ -273,14 +297,14 @@ class CurrencyFieldView extends FloatFieldView {
}
}
if (!this.params.decimal) {
value = parseFloat(value);
if (this.params.decimal) {
return value;
}
return value;
return parseFloat(value);
}
afterRender() {
protected afterRender() {
super.afterRender();
if (this.mode === this.MODE_EDIT) {
@@ -312,16 +336,18 @@ class CurrencyFieldView extends FloatFieldView {
return true;
}
return false;
}
fetch() {
let value = this.$element.val().trim();
fetch(): Record<string, any> {
const valueString = ((this.$element?.val() ?? '') as string).trim();
value = this.parse(value);
const value = this.parse(valueString);
const data = {};
const data = {} as Record<string, any>;
let currencyValue = this.$currency.length ?
let currencyValue: any = this.$currency.length ?
this.$currency.val() :
this.defaultCurrency;

View File

@@ -28,7 +28,12 @@
/** @module views/fields/date */
import BaseFieldView, {BaseOptions as BaseOptions, BaseParams as BaseParams, BaseViewSchema} from 'views/fields/base';
import BaseFieldView, {
BaseOptions as BaseOptions,
BaseParams as BaseParams,
BaseViewSchema,
FieldValidator,
} from 'views/fields/base';
import moment from 'moment';
import Datepicker from 'ui/datepicker';
import JQuery from 'jquery'
@@ -82,7 +87,7 @@ class DateFieldView<
protected editTemplate = 'fields/date/edit'
protected searchTemplate = 'fields/date/search'
protected validations = [
protected validations: (FieldValidator | string)[] = [
'required',
'date',
'after',

View File

@@ -30,7 +30,7 @@
import DateFieldView from 'views/fields/date';
import moment from 'moment';
import {BaseOptions as BaseOptions, BaseViewSchema} from 'views/fields/base';
import {BaseOptions as BaseOptions, BaseViewSchema, FieldValidator} from 'views/fields/base';
import JQuery from 'jquery'
const $ = JQuery;
@@ -86,7 +86,7 @@ class DatetimeFieldView<
protected editTemplate = 'fields/datetime/edit'
protected validations = [
protected validations: (FieldValidator | string)[] = [
'required',
'datetime',
'after',

View File

@@ -29,7 +29,7 @@
/** @module views/fields/float */
import IntFieldView from 'views/fields/int';
import {BaseOptions, BaseParams, BaseViewSchema} from 'views/fields/base';
import {BaseOptions, BaseParams, BaseViewSchema, FieldValidator} from 'views/fields/base';
/**
* Parameters.
@@ -73,12 +73,12 @@ class FloatFieldView<
readonly type: string = 'float'
editTemplate = 'fields/float/edit'
protected editTemplate = 'fields/float/edit'
decimalMark = '.'
decimalPlacesRawValue = 10
protected validations = ['required', 'float', 'range']
protected validations: (FieldValidator | string)[] = ['required', 'float', 'range']
protected setup() {
super.setup();
@@ -177,7 +177,7 @@ class FloatFieldView<
return false;
}
protected parse(input: string): number | null {
protected parse(input: string): number | string | null {
let value = (input !== '') ? input : null;
if (value === null) {

View File

@@ -28,7 +28,7 @@
/** @module views/fields/int */
import BaseFieldView, {BaseOptions, BaseParams, BaseViewSchema} from 'views/fields/base';
import BaseFieldView, {BaseOptions, BaseParams, BaseViewSchema, FieldValidator} from 'views/fields/base';
import AutoNumeric from 'autonumeric';
/**
@@ -74,7 +74,7 @@ class IntFieldView<
protected editTemplate = 'fields/int/edit'
protected searchTemplate = 'fields/int/search'
protected validations = [
protected validations: (FieldValidator | string)[] = [
'required',
'int',
'range',
@@ -364,7 +364,7 @@ class IntFieldView<
return false;
}
protected parse(input: string): number | null {
protected parse(input: string): number | string | null {
let value = (input !== '') ? input : null;
if (value === null) {
@@ -401,14 +401,14 @@ class IntFieldView<
let data: any;
if (value !== null && isNaN(value)) {
if (typeof value === 'number' && isNaN(value)) {
return null;
}
if (type === 'between') {
const valueTo = this.parse(this.$el.find('input.additional').val());
if (valueTo !== null && isNaN(valueTo)) {
if (typeof valueTo === 'number' && isNaN(valueTo)) {
return null;
}

10
package-lock.json generated
View File

@@ -22,7 +22,7 @@
"bootstrap": "github:yurikuzn/espo-bootstrap#0.1.2",
"bootstrap-colorpicker": "^2.5.2",
"bootstrap-datepicker": "^1.9.0",
"bullbone": "github:espocrm/bullbone#1.4.1",
"bullbone": "github:espocrm/bullbone#1.4.2",
"cronstrue": "^1.114.0",
"cropper": "^0.7.9",
"devbridge-autocomplete": "^1.4.11",
@@ -3443,8 +3443,8 @@
}
},
"node_modules/bullbone": {
"version": "1.4.1",
"resolved": "git+ssh://git@github.com/espocrm/bullbone.git#ee78dd11f13a5c29465f218bd2852dfd72a9ceed",
"version": "1.4.2",
"resolved": "git+ssh://git@github.com/espocrm/bullbone.git#aab93904c0bce2d18625c15f8e7487f792ed2b5c",
"license": "AGPL",
"dependencies": {
"snabbdom": "^3.6.3"
@@ -11008,8 +11008,8 @@
"dev": true
},
"bullbone": {
"version": "git+ssh://git@github.com/espocrm/bullbone.git#ee78dd11f13a5c29465f218bd2852dfd72a9ceed",
"from": "bullbone@github:espocrm/bullbone#1.4.1",
"version": "git+ssh://git@github.com/espocrm/bullbone.git#aab93904c0bce2d18625c15f8e7487f792ed2b5c",
"from": "bullbone@github:espocrm/bullbone#1.4.2",
"requires": {
"snabbdom": "^3.6.3"
}

View File

@@ -70,7 +70,7 @@
"bootstrap": "github:yurikuzn/espo-bootstrap#0.1.2",
"bootstrap-colorpicker": "^2.5.2",
"bootstrap-datepicker": "^1.9.0",
"bullbone": "github:espocrm/bullbone#1.4.1",
"bullbone": "github:espocrm/bullbone#1.4.2",
"cronstrue": "^1.114.0",
"cropper": "^0.7.9",
"devbridge-autocomplete": "^1.4.11",