From 7308b0bdbf74fae01dab5fe3afb794cd4bde4804 Mon Sep 17 00:00:00 2001 From: Yurii Date: Tue, 28 Apr 2026 18:23:54 +0300 Subject: [PATCH] TS migration --- client/src/language.js | 2 +- client/src/view.ts | 2 +- client/src/views/fields/base.ts | 31 ++- client/src/views/fields/{date.js => date.ts} | 213 ++++++++----------- client/src/views/fields/varchar.ts | 24 +++ 5 files changed, 134 insertions(+), 138 deletions(-) rename client/src/views/fields/{date.js => date.ts} (80%) diff --git a/client/src/language.js b/client/src/language.js index a6d4fcad88..4a75c4c82f 100644 --- a/client/src/language.js +++ b/client/src/language.js @@ -114,7 +114,7 @@ class Language { * * @param {string} name An item name. * @param {string|'messages'|'labels'|'fields'|'links'|'scopeNames'|'scopeNamesPlural'} [category='labels'] A category. - * @param {string} [scope='Global'] A scope. + * @param {string|null} [scope='Global'] A scope. * @returns {string} */ translate(name, category, scope) { diff --git a/client/src/view.ts b/client/src/view.ts index 287423a39a..97aead50f0 100644 --- a/client/src/view.ts +++ b/client/src/view.ts @@ -337,7 +337,7 @@ export default class View extends BullView { + protected data(): Record { const data = { scope: this.model.entityType || this.model.name, name: this.name, diff --git a/client/src/views/fields/date.js b/client/src/views/fields/date.ts similarity index 80% rename from client/src/views/fields/date.js rename to client/src/views/fields/date.ts index 8551f047a4..4236bd35d8 100644 --- a/client/src/views/fields/date.js +++ b/client/src/views/fields/date.ts @@ -28,70 +28,67 @@ /** @module views/fields/date */ -import BaseFieldView from 'views/fields/base'; +import BaseFieldView, {Options as BaseOptions, Params as BaseParams, ViewSchema} from 'views/fields/base'; import moment from 'moment'; import Datepicker from 'ui/datepicker'; +import JQuery from 'jquery' + +const $ = JQuery; + +interface Params extends BaseParams { + /** + * Required. + */ + required?: boolean; + /** + * Use numeric format. + */ + useNumericFormat?: boolean; + /** + * Validate to be after another date field. + */ + after?: string; + /** + * Validate to be before another date field. + */ + before?: string; + /** + * Allow an equal date for 'after' validation. + */ + afterOrEqual?: boolean; +} + +interface Options extends BaseOptions { + /** + * A label text of other field. Used in before/after validations. + */ + otherFieldLabelText?: string; +} /** * A date field. - * - * @extends BaseFieldView */ -class DateFieldView extends BaseFieldView { +class DateFieldView< + S extends ViewSchema = ViewSchema, + O extends Options = Options, +> extends BaseFieldView { - /** - * @typedef {Object} module:views/fields/date~options - * @property { - * module:views/fields/date~params & - * module:views/fields/base~params & - * Record - * } [params] Parameters. - * @property {string} [otherFieldLabelText] A label text of other field. Used in before/after validations. - */ + readonly type = 'date' - /** - * @typedef {Object} module:views/fields/date~params - * @property {boolean} [required] Required. - * @property {boolean} [useNumericFormat] Use numeric format. - * @property {string} [after] Validate to be after another date field. - * @property {string} [before] Validate to be before another date field. - * @property {boolean} [afterOrEqual] Allow an equal date for 'after' validation. - */ + protected listTemplate = 'fields/date/list' + protected listLinkTemplate = 'fields/date/list-link' + protected detailTemplate = 'fields/date/detail' + protected editTemplate = 'fields/date/edit' + protected searchTemplate = 'fields/date/search' - /** - * @param { - * module:views/fields/date~options & - * module:views/fields/base~options - * } options Options. - */ - constructor(options) { - super(options); - } - - type = 'date' - - listTemplate = 'fields/date/list' - listLinkTemplate = 'fields/date/list-link' - detailTemplate = 'fields/date/detail' - editTemplate = 'fields/date/edit' - searchTemplate = 'fields/date/search' - - /** - * @inheritDoc - * @type {Array<(function (): boolean)|string>} - */ - validations = [ + protected validations = [ 'required', 'date', 'after', 'before', ] - /** - * @protected - * @type {string[]} - */ - searchTypeList = [ + protected searchTypeList = [ 'lastSevenDays', 'ever', 'isEmpty', @@ -115,30 +112,18 @@ class DateFieldView extends BaseFieldView { 'between', ] - /** - * @protected - * @type {string[]} - */ - searchWithPrimaryTypeList = [ + protected searchWithPrimaryTypeList: string[] = [ 'on', 'notOn', 'after', 'before', ] - /** - * @protected - * @type {string[]} - */ - searchWithRangeTypeList = [ + protected searchWithRangeTypeList: string[] = [ 'between', ] - /** - * @protected - * @type {string[]} - */ - searchWithAdditionalNumberTypeList = [ + protected searchWithAdditionalNumberTypeList: string[] = [ 'lastXDays', 'nextXDays', 'olderThanXDays', @@ -148,21 +133,13 @@ class DateFieldView extends BaseFieldView { /** * @inheritDoc */ - initialSearchIsNotIdle = true + initialSearchIsNotIdle: boolean = true - /** - * @private - * @type {import('ui/datepicker').default} - */ - datepicker + private datepicker: Datepicker | null = null - /** - * @protected - * @type {boolean} - */ - useNumericFormat + protected useNumericFormat: boolean - setup() { + protected setup() { super.setup(); if (this.getConfig().get('fiscalYearShift')) { @@ -189,7 +166,7 @@ class DateFieldView extends BaseFieldView { setTimeout(() => { this.onAfterChange(); - this.datepicker.setStartDate(this.getStartDateForDatePicker()); + this.datepicker?.setStartDate(this.getStartDateForDatePicker()); }, 100); }); } @@ -197,8 +174,7 @@ class DateFieldView extends BaseFieldView { this.useNumericFormat = this.getConfig().get('readableDateFormatDisabled') || this.params.useNumericFormat; } - // noinspection JSCheckFunctionSignatures - data() { + protected data() { const data = super.data(); data.dateValue = this.getDateStringValue(); @@ -211,14 +187,14 @@ class DateFieldView extends BaseFieldView { } if (this.isSearchMode()) { - const value = this.getSearchParamsData().value || this.searchParams.dateValue; - const valueTo = this.getSearchParamsData().valueTo || this.searchParams.dateValueTo; + const value = this.getSearchParamsData().value || this.searchParams?.dateValue; + const valueTo = this.getSearchParamsData().valueTo || this.searchParams?.dateValueTo; data.dateValue = this.getDateTime().toDisplayDate(value); data.dateValueTo = this.getDateTime().toDisplayDate(valueTo); if (this.searchWithAdditionalNumberTypeList.includes(this.getSearchType())) { - data.number = this.searchParams.value; + data.number = this.searchParams?.value; } } @@ -235,8 +211,8 @@ class DateFieldView extends BaseFieldView { } setupSearch() { - this.addHandler('change', 'select.search-type', (e, /** HTMLSelectElement */target) => { - this.handleSearchType(target.value); + this.addHandler('change', 'select.search-type', (_e, target) => { + this.handleSearchType((target as HTMLSelectElement).value); this.trigger('change'); }); @@ -244,7 +220,7 @@ class DateFieldView extends BaseFieldView { this.addHandler('change', 'input.number', () => this.trigger('change')); } - stringifyDateValue(value) { + protected stringifyDateValue(value: any): string | null { if (!value) { if ( this.mode === this.MODE_EDIT || @@ -269,7 +245,7 @@ class DateFieldView extends BaseFieldView { return this.getDateTime().toDisplayDate(value); } - convertDateValueForDetail(value) { + protected convertDateValueForDetail(value: any): string | null { if (this.useNumericFormat) { return this.getDateTime().toDisplayDate(value); } @@ -279,7 +255,9 @@ class DateFieldView extends BaseFieldView { const readableFormat = this.getDateTime().getReadableDateFormat(); const valueWithTime = value + ' 00:00:00'; + // @ts-ignore const today = moment.tz(timezone).startOf('day'); + // @ts-ignore let dateTime = moment.tz(valueWithTime, internalDateTimeFormat, timezone); const temp = today.clone(); @@ -312,7 +290,7 @@ class DateFieldView extends BaseFieldView { return dateTime.format(readableFormat + ', YYYY'); } - getDateStringValue() { + protected getDateStringValue(): string | -1 | null { if (this.mode === this.MODE_DETAIL && !this.model.has(this.name)) { return -1; } @@ -322,16 +300,11 @@ class DateFieldView extends BaseFieldView { return this.stringifyDateValue(value); } - /** - * @protected - * @return {string|undefined} - */ - getStartDateForDatePicker() { + protected getStartDateForDatePicker(): string | undefined { if (!this.isEditMode() || !this.params.after) { return undefined; } - /** @type {string} */ let date = this.model.attributes[this.params.after]; if (date == null) { @@ -352,7 +325,7 @@ class DateFieldView extends BaseFieldView { if (this.isEditMode() || this.isSearchMode()) { this.mainInputElement = this.element?.querySelector(`[data-name="${this.name}"]`); - this.$element = $(this.mainInputElement); + this.$element = $(this.mainInputElement as any); const options = { format: this.getDateTime().dateFormat, @@ -361,7 +334,7 @@ class DateFieldView extends BaseFieldView { todayButton: this.getConfig().get('datepickerTodayButton') || false, }; - this.datepicker = undefined; + this.datepicker = null; if (this.mainInputElement instanceof HTMLInputElement) { this.datepicker = new Datepicker(this.mainInputElement, { @@ -371,7 +344,7 @@ class DateFieldView extends BaseFieldView { } if (this.isSearchMode()) { - const additionalGroup = this.element?.querySelector('.input-group.additional'); + const additionalGroup = this.element?.querySelector('.input-group.additional') as HTMLElement | null; if (additionalGroup) { new Datepicker(additionalGroup, options) @@ -381,10 +354,10 @@ class DateFieldView extends BaseFieldView { } } - const button = this.mainInputElement?.parentNode.querySelector('button.date-picker-btn'); + const button = this.mainInputElement?.parentNode?.querySelector('button.date-picker-btn'); if (button instanceof HTMLElement) { - button.addEventListener('click', () => this.datepicker.show()); + button.addEventListener('click', () => this.datepicker?.show()); } if (this.isSearchMode()) { @@ -399,14 +372,14 @@ class DateFieldView extends BaseFieldView { * @private * @param {string} selector */ - initDatePickerEventHandlers(selector) { + initDatePickerEventHandlers(selector: string) { const input = this.element?.querySelector(selector); if (!(input instanceof HTMLInputElement)) { return; } - $(input).on('change', /** Record */e => { + $(input).on('change', (e: Record) => { this.trigger('change'); if (e.isTrigger) { @@ -417,11 +390,7 @@ class DateFieldView extends BaseFieldView { }); } - /** - * @protected - * @param {string} type - */ - handleSearchType(type) { + protected handleSearchType(type: string) { const primary = this.element?.querySelector('div.primary'); const additional = this.element?.querySelector('div.additional'); const additionalNumber = this.element?.querySelector('div.additional-number'); @@ -447,20 +416,11 @@ class DateFieldView extends BaseFieldView { } } - /** - * @protected - * @param {string} string - * @return {string|-1} - */ - parseDate(string) { + protected parseDate(string: string): string | -1 { return this.getDateTime().fromDisplayDate(string); } - /** - * @param {string} string - * @return {string|-1|null} - */ - parse(string) { + protected parse(string: string): string | -1 | null { if (!string) { return null; } @@ -468,11 +428,8 @@ class DateFieldView extends BaseFieldView { return this.parseDate(string); } - /** - * @inheritDoc - */ - fetch() { - const data = {}; + fetch(): Record { + const data = {} as Record; data[this.name] = this.parse(this.mainInputElement?.value ?? ''); @@ -552,12 +509,12 @@ class DateFieldView extends BaseFieldView { } getSearchType() { - return this.getSearchParamsData().type || this.searchParams.typeFront || this.searchParams.type; + return this.getSearchParamsData().type ?? this.searchParams?.typeFront ?? this.searchParams?.type ?? null; } validateRequired() { if (!this.isRequired()) { - return; + return false; } if (this.model.get(this.name) === null) { @@ -568,6 +525,8 @@ class DateFieldView extends BaseFieldView { return true; } + + return false; } // noinspection JSUnusedGlobalSymbols @@ -651,10 +610,10 @@ class DateFieldView extends BaseFieldView { * @since 9.2.0 */ onAfterChange() { - /** @type {string} */ - const from = this.model.attributes[this.params.after]; - /** @type {string} */ - const currentValue = this.model.attributes[this.name]; + const after = this.params.after as string; + + const from = this.model.attributes[after] as string | undefined; + const currentValue = this.model.attributes[this.name] as string | undefined; if (!from || !currentValue || from.length !== currentValue.length) { return; diff --git a/client/src/views/fields/varchar.ts b/client/src/views/fields/varchar.ts index 8491f25ef8..e3ae418d7e 100644 --- a/client/src/views/fields/varchar.ts +++ b/client/src/views/fields/varchar.ts @@ -36,16 +36,40 @@ import Ajax from 'ajax'; import Ui from 'ui'; interface Params extends BaseParams { + /** + * Max length. + */ maxLength?: number; + /** + * Autocomplete options. + */ options?: string[]; + /** + * Is required. + */ required?: boolean; + /** + * Options path. + */ optionsPath?: string; + /** + * No spell check. + */ noSpellCheck?: boolean; + /** + * A pattern. + */ pattern?: string; + /** + * Show 'Copy to Clipboard' button. + */ copyToClipboard?: boolean; } interface Options extends BaseOptions { + /** + * Custom autocomplete options. + */ customOptionList?: string[]; }