Skip to content

Commit aeb1057

Browse files
committed
lint
1 parent 7192ec7 commit aeb1057

9 files changed

Lines changed: 83 additions & 59 deletions

File tree

packages/components/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/components/releaseNotes/components.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ Components, models, actions, and utility functions for LabKey applications and p
44
### version 6.X
55
*Released*: X May 2025
66
- Issue 53071: Entering more than three digits for milliseconds in a time field causes the value to disappear
7+
- Issue 52820: Sample Manager: editing datetime/time fields in app with display format could result in time precision loss
78
- Updated `parseTime` util to be more flexible
9+
- TODO
810

911
### version 6.44.4
1012
*Released*: 2 June 2025

packages/components/src/internal/components/EditInlineField.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
getColDateFormat,
77
getDateFNSDateFormat,
88
getJsonDateTimeFormatString,
9-
getJsonDateFormatString, getJsonTimeFormatString,
9+
getJsonDateFormatString,
10+
getJsonTimeFormatString,
1011
} from '../util/Date';
1112
import { Key, useEnterEscape } from '../../public/useEnterEscape';
1213

@@ -145,13 +146,10 @@ export const EditInlineField: FC<Props> = memo(props => {
145146
setState({ ignoreBlur: false });
146147
}, [allowBlank, getInputValue, isDate, onCancel, saveEdit, state.ignoreBlur]);
147148

148-
const onDateChange = useCallback(
149-
(date: Date) => {
150-
if (date instanceof Array) throw new Error('Unsupported date/time type');
151-
setDateValue(date);
152-
},
153-
[]
154-
);
149+
const onDateChange = useCallback((date: Date) => {
150+
if (date instanceof Array) throw new Error('Unsupported date/time type');
151+
setDateValue(date);
152+
}, []);
155153

156154
const onFormsyColumnChange = useCallback(
157155
(data: Record<string, any>) => {

packages/components/src/internal/components/editable/Cell.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,14 @@ export interface CellProps extends SharedProps {
178178
containerPath?: string;
179179
focused?: boolean;
180180
forUpdate: boolean;
181+
getDisplayValue?: (vd: ValueDescriptor) => string;
181182
linkedValues?: any[];
182183
name?: string;
183184
readOnly?: boolean;
184185
renderDragHandle?: boolean;
185186
row?: any;
186187
rowIdx: number;
187188
values?: List<ValueDescriptor>;
188-
getDisplayValue?: (vd: ValueDescriptor) => string;
189189
}
190190

191191
interface State {
@@ -542,7 +542,7 @@ export class Cell extends React.PureComponent<CellProps, State> {
542542
selection,
543543
values,
544544
containerPath,
545-
getDisplayValue
545+
getDisplayValue,
546546
} = this.props;
547547

548548
const alignRight = col.align === 'right';
@@ -551,8 +551,7 @@ export class Cell extends React.PureComponent<CellProps, State> {
551551
if (!focused) {
552552
const displayValue = values
553553
.filter(vd => vd && vd.display !== undefined)
554-
.reduce((v, vd, i) =>
555-
v + (i > 0 ? ', ' : '') + (getDisplayValue?.(vd) ?? vd.display), '');
554+
.reduce((v, vd, i) => v + (i > 0 ? ', ' : '') + (getDisplayValue?.(vd) ?? vd.display), '');
556555

557556
return (
558557
<>

packages/components/src/internal/components/editable/DateInputCell.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ export const DateInputCell: FC<DateInputCellProps> = memo(props => {
3939
if (!display) {
4040
if (newDate && typeof newDate === 'string') display = newDate;
4141
else if (newDate && newDate instanceof Date) {
42-
display = col.isTimeColumn ? formatTime(newDate): (isDateTimeCol(col) ? formatDateTime(newDate) : formatDate(newDate));
42+
display = col.isTimeColumn
43+
? formatTime(newDate)
44+
: isDateTimeCol(col)
45+
? formatDateTime(newDate)
46+
: formatDate(newDate);
4347
}
4448
}
4549

packages/components/src/internal/components/editable/EditableGrid.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ import { LabelOverlay } from '../forms/LabelOverlay';
4949

5050
import { DropdownMenu } from '../../dropdowns';
5151

52+
import { formatDateTimeDisplayValueForUpdate } from '../../util/Date';
53+
5254
import {
5355
addRows,
5456
addRowsPerPivotValue,
@@ -73,7 +75,6 @@ import { AddRowsControl, AddRowsControlProps, PlacementType } from './Controls';
7375
import { CellMessage, EditableColumnMetadata, EditorModel, EditorModelProps, ValueDescriptor } from './models';
7476
import { computeRangeChange, genCellKey, getValidatedEditableGridValue, parseCellKey } from './utils';
7577
import { RemoveColumnMenuItem } from './RemoveColumnMenuItem';
76-
import { formatDateTimeDisplayValueForUpdate } from '../../util/Date';
7778

7879
function anyCell(values: List<ValueDescriptor>): boolean {
7980
return true;
@@ -170,7 +171,7 @@ function inputCellFactory(
170171
forUpdate: boolean,
171172
initialSelection: string[],
172173
containerPath?: string,
173-
getDisplayValue?: (vd: ValueDescriptor) => string,
174+
getDisplayValue?: (vd: ValueDescriptor) => string
174175
): GridColumnCellRenderer {
175176
// Note: We ignore the incoming value (_) and rowNumber (__) because they come from the underlying QueryModel that
176177
// backs the Grid component, but we need to reference the data that is in the EditorModel.
@@ -877,9 +878,9 @@ export class EditableGrid extends PureComponent<EditableGridProps, EditableGridS
877878
const hideTooltip = metadata?.hideTitleTooltip ?? qCol.hasHelpTipData;
878879
let getDisplayValue = null;
879880
if (qCol.isTimeColumn || qCol.jsonType === 'date') {
880-
getDisplayValue = (vd) => {
881+
getDisplayValue = vd => {
881882
return formatDateTimeDisplayValueForUpdate(vd, qCol);
882-
}
883+
};
883884
}
884885
gridColumns = gridColumns.push(
885886
new GridColumn({

packages/components/src/internal/components/forms/QueryInfoForm.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ import { QueryFormInputs, QueryFormInputsProps } from './QueryFormInputs';
4242
import { getFieldEnabledFieldName } from './utils';
4343
import { CommentTextArea } from './input/CommentTextArea';
4444

45-
export const getUpdatedFields = (queryInfo: QueryInfo, data: any, submitForEdit?: boolean, additionalFields?: string[]): OrderedMap<string, any> => {
45+
export const getUpdatedFields = (
46+
queryInfo: QueryInfo,
47+
data: any,
48+
submitForEdit?: boolean,
49+
additionalFields?: string[]
50+
): OrderedMap<string, any> => {
4651
const fieldsToUpdate = queryInfo.columns.filter(column => {
4752
const enabledKey = getFieldEnabledFieldName(column);
4853
return data[enabledKey] === undefined || data[enabledKey] === 'true';
@@ -187,7 +192,10 @@ export class QueryInfoForm extends PureComponent<QueryInfoFormProps, State> {
187192
if (onFormChangeWithData) {
188193
const row = this.formRef?.['current']?.['getModel']?.();
189194
if (row) {
190-
const updatedRow = getUpdatedFields(queryInfo, row, this.state.submitForEdit, ['numItems', 'creationType']);
195+
const updatedRow = getUpdatedFields(queryInfo, row, this.state.submitForEdit, [
196+
'numItems',
197+
'creationType',
198+
]);
191199
onFormChangeWithData(updatedRow);
192200
}
193201
}

packages/components/src/internal/components/forms/input/DatePickerInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export class DatePickerInputImpl extends DisableableInput<DatePickerInputImplPro
155155

156156
getInitDate(props: DatePickerInputProps, minDate?: Date): Date {
157157
const { allowRelativeInput, queryColumn, value } = props;
158-
return getDateFromISO(value, queryColumn, allowRelativeInput, minDate)
158+
return getDateFromISO(value, queryColumn, allowRelativeInput, minDate);
159159
}
160160

161161
onChange = (date: Date, event?: any, raw?: boolean): void => {

packages/components/src/internal/util/Date.ts

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -101,35 +101,31 @@ export function isDateTimeCol(col: QueryColumn): boolean {
101101
}
102102

103103
function _toAmPm(rawTimeFormat: string, toAMPM: boolean) {
104-
if (!toAMPM)
105-
return rawTimeFormat;
104+
if (!toAMPM) return rawTimeFormat;
106105

107-
if (rawTimeFormat.indexOf(' a') > -1)
108-
return rawTimeFormat;
106+
if (rawTimeFormat.indexOf(' a') > -1) return rawTimeFormat;
109107

110108
return rawTimeFormat.replace('HH', 'hh') + ' a';
111-
112109
}
113110

114-
export function getPickerTimeFormatWithPrecision(timeFormat: string, showMinute: boolean, showSeconds: boolean, showMilliSeconds: boolean) {
111+
export function getPickerTimeFormatWithPrecision(
112+
timeFormat: string,
113+
showMinute: boolean,
114+
showSeconds: boolean,
115+
showMilliSeconds: boolean
116+
) {
115117
const useAmPm = timeFormat.indexOf(' a') > -1;
116-
if (timeFormat.indexOf('.SSS') > -1)
117-
return timeFormat;
118+
if (timeFormat.indexOf('.SSS') > -1) return timeFormat;
118119

119-
if (showMilliSeconds)
120-
return _toAmPm(ISO_LONG_TIME_FORMAT_STRING, useAmPm);
120+
if (showMilliSeconds) return _toAmPm(ISO_LONG_TIME_FORMAT_STRING, useAmPm);
121121

122-
if (timeFormat.indexOf(':ss') > -1)
123-
return timeFormat;
122+
if (timeFormat.indexOf(':ss') > -1) return timeFormat;
124123

125-
if (showSeconds)
126-
return _toAmPm(ISO_TIME_FORMAT_STRING, useAmPm);
124+
if (showSeconds) return _toAmPm(ISO_TIME_FORMAT_STRING, useAmPm);
127125

128-
if (timeFormat.indexOf(':mm') > -1)
129-
return timeFormat;
126+
if (timeFormat.indexOf(':mm') > -1) return timeFormat;
130127

131-
if (showMinute)
132-
return _toAmPm(ISO_SHORT_TIME_FORMAT_STRING, useAmPm);
128+
if (showMinute) return _toAmPm(ISO_SHORT_TIME_FORMAT_STRING, useAmPm);
133129

134130
return timeFormat;
135131
}
@@ -138,11 +134,19 @@ export function getPickerTimeFormatWithPrecision(timeFormat: string, showMinute:
138134
// for example:
139135
// 'yyyy-MM-dd HH:mm' -> 'yyyy-MM-dd HH:mm:ss' if showSeconds is true and showMilliSeconds is false
140136
// 'yyyy-MM-dd hh:mm a' -> 'yyyy-MM-dd hh:mm:ss.SSS a' if showSeconds is true and showMilliSeconds is true
141-
export function getPickerFormatWithPrecision(rawDateTimeFormat: string, showMinute: boolean, showSeconds: boolean, showMilliSeconds: boolean) {
137+
export function getPickerFormatWithPrecision(
138+
rawDateTimeFormat: string,
139+
showMinute: boolean,
140+
showSeconds: boolean,
141+
showMilliSeconds: boolean
142+
) {
142143
const parts = splitDateTimeFormat(rawDateTimeFormat);
143-
if (parts.length === 1)
144-
return parts[0];
145-
return (parts[0] + ' ' + getPickerTimeFormatWithPrecision(parts[1], showMinute, showSeconds, showMilliSeconds)).trim();
144+
if (parts.length === 1) return parts[0];
145+
return (
146+
parts[0] +
147+
' ' +
148+
getPickerTimeFormatWithPrecision(parts[1], showMinute, showSeconds, showMilliSeconds)
149+
).trim();
146150
}
147151

148152
export function getPickerDateAndTimeFormat(
@@ -152,25 +156,38 @@ export function getPickerDateAndTimeFormat(
152156
): { dateFormat: string; timeFormat: string } {
153157
const hasMsPrecision = initDate?.getMilliseconds() > 0;
154158
const hasSecondsPrecision = hasMsPrecision || initDate?.getSeconds() > 0;
155-
const hasMinutePrecision = hasSecondsPrecision || initDate?.getMinutes() > 0 || initDate?.getHours() > 0;
159+
const hasMinutePrecision = hasSecondsPrecision || initDate?.getMinutes() > 0 || initDate?.getHours() > 0;
156160

157161
const dateFormat_ = getColDateFormat(column, hideTime ? DateFormatType.Date : undefined, column.isDateOnlyColumn);
158-
let dateFormat = column.isTimeColumn || column.isDateOnlyColumn ? dateFormat_ : getPickerFormatWithPrecision(dateFormat_, hasMinutePrecision, hasSecondsPrecision, hasMsPrecision);
162+
let dateFormat =
163+
column.isTimeColumn || column.isDateOnlyColumn
164+
? dateFormat_
165+
: getPickerFormatWithPrecision(dateFormat_, hasMinutePrecision, hasSecondsPrecision, hasMsPrecision);
159166
let timeFormat: string;
160167
if (!hideTime) {
161168
if (column.isTimeColumn) {
162169
timeFormat = parseFNSTimeFormat(getColDateFormat(column, column?.format ?? DateFormatType.Time));
163-
timeFormat = getPickerTimeFormatWithPrecision(timeFormat, hasMinutePrecision, hasSecondsPrecision, hasMsPrecision);
170+
timeFormat = getPickerTimeFormatWithPrecision(
171+
timeFormat,
172+
hasMinutePrecision,
173+
hasSecondsPrecision,
174+
hasMsPrecision
175+
);
164176
dateFormat = timeFormat;
165177
} else {
166178
timeFormat = parseDateFNSTimeFormat(dateFormat);
167179
}
168180
}
169181

170-
return {dateFormat, timeFormat };
182+
return { dateFormat, timeFormat };
171183
}
172184

173-
export function getDateFromISO(value: string, queryColumn: QueryColumn, allowRelativeInput?: boolean, minDate?: Date): Date {
185+
export function getDateFromISO(
186+
value: string,
187+
queryColumn: QueryColumn,
188+
allowRelativeInput?: boolean,
189+
minDate?: Date
190+
): Date {
174191
if (!value || (allowRelativeInput && isRelativeDateFilterValue(value))) return undefined;
175192

176193
if (queryColumn.isTimeColumn) {
@@ -182,12 +199,10 @@ export function getDateFromISO(value: string, queryColumn: QueryColumn, allowRel
182199

183200
export function formatDateTimeDisplayValueForUpdate(vd: ValueDescriptor, queryColumn: QueryColumn): string {
184201
const isoValue = vd?.raw;
185-
if (!isoValue)
186-
return null;
202+
if (!isoValue) return null;
187203
const date = getDateFromISO(isoValue, queryColumn);
188-
const {dateFormat, timeFormat} = getPickerDateAndTimeFormat(queryColumn, false, date);
189-
if (queryColumn.isTimeColumn)
190-
return formatTime(isoValue, timeFormat);
204+
const { dateFormat, timeFormat } = getPickerDateAndTimeFormat(queryColumn, false, date);
205+
if (queryColumn.isTimeColumn) return formatTime(isoValue, timeFormat);
191206
return formatDate(date, null, dateFormat);
192207
}
193208

@@ -469,12 +484,9 @@ export function parseTime(time: string | Date): Date {
469484
if (!time) return null;
470485

471486
if (time instanceof Date) {
472-
if (isValid(time))
473-
return time;
474-
return null;
475-
}
476-
else if (typeof time !== 'string')
487+
if (isValid(time)) return time;
477488
return null;
489+
} else if (typeof time !== 'string') return null;
478490

479491
// Regular expressions for different time formats
480492
const timeFormats = [

0 commit comments

Comments
 (0)