added a DateAndTimeService on the frontend to get those functions out of helpers w/ burnettk (#560)
Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
54b7c5c3ec
commit
5907339918
|
@ -2,7 +2,8 @@ import { useEffect, useState } from 'react';
|
|||
|
||||
import HttpService from '../services/HttpService';
|
||||
import { User } from '../interfaces';
|
||||
import { refreshAtInterval, REFRESH_TIMEOUT_SECONDS } from '../helpers';
|
||||
import { refreshAtInterval } from '../helpers';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
|
||||
async function sha256(message: string) {
|
||||
// encode as UTF-8
|
||||
|
@ -48,7 +49,7 @@ export default function ActiveUsers() {
|
|||
|
||||
return refreshAtInterval(
|
||||
15,
|
||||
REFRESH_TIMEOUT_SECONDS,
|
||||
DateAndTimeService.REFRESH_TIMEOUT_SECONDS,
|
||||
updateActiveUsers,
|
||||
unregisterUser
|
||||
);
|
||||
|
|
|
@ -7,13 +7,13 @@ import { Link, useSearchParams } from 'react-router-dom';
|
|||
import PaginationForTable from './PaginationForTable';
|
||||
import ProcessBreadcrumb from './ProcessBreadcrumb';
|
||||
import {
|
||||
convertSecondsToFormattedDateTime,
|
||||
getPageInfoFromSearchParams,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
} from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { FormatProcessModelDisplayName } from './MiniComponents';
|
||||
import { MessageInstance } from '../interfaces';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
|
||||
type OwnProps = {
|
||||
processInstanceId?: number;
|
||||
|
@ -128,7 +128,9 @@ export default function MessageInstanceList({ processInstanceId }: OwnProps) {
|
|||
</td>
|
||||
<td>{row.status}</td>
|
||||
<td>
|
||||
{convertSecondsToFormattedDateTime(row.created_at_in_seconds)}
|
||||
{DateAndTimeService.convertSecondsToFormattedDateTime(
|
||||
row.created_at_in_seconds
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
|
|
@ -36,22 +36,13 @@ import {
|
|||
DATE_FORMAT_FOR_DISPLAY,
|
||||
} from '../config';
|
||||
import {
|
||||
convertDateAndTimeStringsToSeconds,
|
||||
convertDateObjectToFormattedHoursMinutes,
|
||||
convertSecondsToFormattedDateString,
|
||||
convertSecondsToFormattedDateTime,
|
||||
convertSecondsToFormattedTimeHoursMinutes,
|
||||
getKeyByValue,
|
||||
getLastMilestoneFromProcessInstance,
|
||||
getPageInfoFromSearchParams,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
refreshAtInterval,
|
||||
REFRESH_INTERVAL_SECONDS,
|
||||
REFRESH_TIMEOUT_SECONDS,
|
||||
titleizeString,
|
||||
truncateString,
|
||||
formatDurationForDisplay,
|
||||
formatDateTime,
|
||||
} from '../helpers';
|
||||
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
||||
|
||||
|
@ -86,6 +77,7 @@ import { Can } from '../contexts/Can';
|
|||
import TableCellWithTimeAgoInWords from './TableCellWithTimeAgoInWords';
|
||||
import UserService from '../services/UserService';
|
||||
import Filters from './Filters';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
|
||||
type OwnProps = {
|
||||
filtersEnabled?: boolean;
|
||||
|
@ -443,13 +435,15 @@ export default function ProcessInstanceListTable({
|
|||
const timeFunctionToCall =
|
||||
dateParametersToAlwaysFilterBy[reportFilter.field_name][1];
|
||||
if (reportFilter.field_value) {
|
||||
const dateString = convertSecondsToFormattedDateString(
|
||||
reportFilter.field_value as any
|
||||
);
|
||||
const dateString =
|
||||
DateAndTimeService.convertSecondsToFormattedDateString(
|
||||
reportFilter.field_value as any
|
||||
);
|
||||
dateFunctionToCall(dateString);
|
||||
const timeString = convertSecondsToFormattedTimeHoursMinutes(
|
||||
reportFilter.field_value as any
|
||||
);
|
||||
const timeString =
|
||||
DateAndTimeService.convertSecondsToFormattedTimeHoursMinutes(
|
||||
reportFilter.field_value as any
|
||||
);
|
||||
timeFunctionToCall(timeString);
|
||||
}
|
||||
}
|
||||
|
@ -566,8 +560,8 @@ export default function ProcessInstanceListTable({
|
|||
checkFiltersAndRun();
|
||||
if (autoReload) {
|
||||
clearRefreshRef.current = refreshAtInterval(
|
||||
REFRESH_INTERVAL_SECONDS,
|
||||
REFRESH_TIMEOUT_SECONDS,
|
||||
DateAndTimeService.REFRESH_INTERVAL_SECONDS,
|
||||
DateAndTimeService.REFRESH_TIMEOUT_SECONDS,
|
||||
checkFiltersAndRun
|
||||
);
|
||||
return clearRefreshRef.current;
|
||||
|
@ -627,19 +621,22 @@ export default function ProcessInstanceListTable({
|
|||
// with the use of the setErrorMessageSafely function. we are not sure why the context not
|
||||
// changing still causes things to rerender when we call its setter without our extra check.
|
||||
const calculateStartAndEndSeconds = (validate: boolean = true) => {
|
||||
const startFromSeconds = convertDateAndTimeStringsToSeconds(
|
||||
startFromDate,
|
||||
startFromTime || '00:00:00'
|
||||
);
|
||||
const startToSeconds = convertDateAndTimeStringsToSeconds(
|
||||
startToDate,
|
||||
startToTime || '00:00:00'
|
||||
);
|
||||
const endFromSeconds = convertDateAndTimeStringsToSeconds(
|
||||
endFromDate,
|
||||
endFromTime || '00:00:00'
|
||||
);
|
||||
const endToSeconds = convertDateAndTimeStringsToSeconds(
|
||||
const startFromSeconds =
|
||||
DateAndTimeService.convertDateAndTimeStringsToSeconds(
|
||||
startFromDate,
|
||||
startFromTime || '00:00:00'
|
||||
);
|
||||
const startToSeconds =
|
||||
DateAndTimeService.convertDateAndTimeStringsToSeconds(
|
||||
startToDate,
|
||||
startToTime || '00:00:00'
|
||||
);
|
||||
const endFromSeconds =
|
||||
DateAndTimeService.convertDateAndTimeStringsToSeconds(
|
||||
endFromDate,
|
||||
endFromTime || '00:00:00'
|
||||
);
|
||||
const endToSeconds = DateAndTimeService.convertDateAndTimeStringsToSeconds(
|
||||
endToDate,
|
||||
endToTime || '00:00:00'
|
||||
);
|
||||
|
@ -872,7 +869,9 @@ export default function ProcessInstanceListTable({
|
|||
onChange={(dateChangeEvent: any) => {
|
||||
if (!initialDate && !initialTime) {
|
||||
onChangeTimeFunction(
|
||||
convertDateObjectToFormattedHoursMinutes(new Date())
|
||||
DateAndTimeService.convertDateObjectToFormattedHoursMinutes(
|
||||
new Date()
|
||||
)
|
||||
);
|
||||
}
|
||||
onChangeDateFunction(dateChangeEvent.srcElement.value);
|
||||
|
@ -1691,7 +1690,7 @@ export default function ProcessInstanceListTable({
|
|||
};
|
||||
|
||||
const formatSecondsForDisplay = (_row: ProcessInstance, seconds: any) => {
|
||||
return convertSecondsToFormattedDateTime(seconds) || '-';
|
||||
return DateAndTimeService.convertSecondsToFormattedDateTime(seconds) || '-';
|
||||
};
|
||||
const defaultFormatter = (_row: ProcessInstance, value: any) => {
|
||||
return value;
|
||||
|
@ -1710,8 +1709,8 @@ export default function ProcessInstanceListTable({
|
|||
last_milestone_bpmn_name: formatLastMilestone,
|
||||
};
|
||||
const displayTypeFormatters: Record<string, any> = {
|
||||
date_time: formatDateTime,
|
||||
duration: formatDurationForDisplay,
|
||||
date_time: DateAndTimeService.formatDateTime,
|
||||
duration: DateAndTimeService.formatDurationForDisplay,
|
||||
};
|
||||
const columnAccessor = column.accessor as keyof ProcessInstance;
|
||||
const formatter = column.display_type
|
||||
|
|
|
@ -15,7 +15,6 @@ import { createSearchParams, Link, useSearchParams } from 'react-router-dom';
|
|||
import PaginationForTable from './PaginationForTable';
|
||||
import {
|
||||
getPageInfoFromSearchParams,
|
||||
convertSecondsToFormattedDateTime,
|
||||
selectKeysFromSearchParams,
|
||||
} from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
|
@ -32,6 +31,7 @@ import {
|
|||
childrenForErrorObject,
|
||||
errorForDisplayFromProcessInstanceErrorDetail,
|
||||
} from './ErrorDisplay';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
|
||||
type OwnProps = {
|
||||
variant: string; // 'all' or 'for-me'
|
||||
|
@ -306,7 +306,11 @@ export default function ProcessInstanceLogList({
|
|||
}
|
||||
|
||||
let timestampComponent = (
|
||||
<td>{convertSecondsToFormattedDateTime(logEntry.timestamp)}</td>
|
||||
<td>
|
||||
{DateAndTimeService.convertSecondsToFormattedDateTime(
|
||||
logEntry.timestamp
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
if (logEntry.spiff_task_guid && logEntry.event_type !== 'task_cancelled') {
|
||||
timestampComponent = (
|
||||
|
@ -317,7 +321,9 @@ export default function ProcessInstanceLogList({
|
|||
to={`${processInstanceShowPageBaseUrl}/${logEntry.process_instance_id}/${logEntry.spiff_task_guid}`}
|
||||
title="View state when task was completed"
|
||||
>
|
||||
{convertSecondsToFormattedDateTime(logEntry.timestamp)}
|
||||
{DateAndTimeService.convertSecondsToFormattedDateTime(
|
||||
logEntry.timestamp
|
||||
)}
|
||||
</Link>
|
||||
</td>
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @ts-ignore
|
||||
import { TimeAgo } from '../helpers/timeago';
|
||||
import { convertSecondsToFormattedDateTime } from '../helpers';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
|
||||
type OwnProps = {
|
||||
timeInSeconds: number;
|
||||
|
@ -16,7 +16,10 @@ export default function TableCellWithTimeAgoInWords({
|
|||
return (
|
||||
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
|
||||
<td
|
||||
title={convertSecondsToFormattedDateTime(timeInSeconds) || '-'}
|
||||
title={
|
||||
DateAndTimeService.convertSecondsToFormattedDateTime(timeInSeconds) ||
|
||||
'-'
|
||||
}
|
||||
onClick={onClick}
|
||||
onKeyDown={onKeyDown}
|
||||
>
|
||||
|
|
|
@ -6,18 +6,16 @@ import { TimeAgo } from '../helpers/timeago';
|
|||
import UserService from '../services/UserService';
|
||||
import PaginationForTable from './PaginationForTable';
|
||||
import {
|
||||
convertSecondsToFormattedDateTime,
|
||||
getPageInfoFromSearchParams,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
refreshAtInterval,
|
||||
REFRESH_INTERVAL_SECONDS,
|
||||
REFRESH_TIMEOUT_SECONDS,
|
||||
} from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { PaginationObject, ProcessInstanceTask, Task } from '../interfaces';
|
||||
import TableCellWithTimeAgoInWords from './TableCellWithTimeAgoInWords';
|
||||
import CustomForm from './CustomForm';
|
||||
import InstructionsForEndUser from './InstructionsForEndUser';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
|
||||
const PER_PAGE_FOR_TASKS_ON_HOME_PAGE = 5;
|
||||
|
||||
|
@ -100,8 +98,8 @@ export default function TaskListTable({
|
|||
getTasks();
|
||||
if (autoReload) {
|
||||
return refreshAtInterval(
|
||||
REFRESH_INTERVAL_SECONDS,
|
||||
REFRESH_TIMEOUT_SECONDS,
|
||||
DateAndTimeService.REFRESH_INTERVAL_SECONDS,
|
||||
DateAndTimeService.REFRESH_TIMEOUT_SECONDS,
|
||||
getTasks
|
||||
);
|
||||
}
|
||||
|
@ -288,7 +286,7 @@ export default function TaskListTable({
|
|||
if (showDateStarted) {
|
||||
rowElements.push(
|
||||
<td>
|
||||
{convertSecondsToFormattedDateTime(
|
||||
{DateAndTimeService.convertSecondsToFormattedDateTime(
|
||||
processInstanceTask.created_at_in_seconds
|
||||
) || '-'}
|
||||
</td>
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import {
|
||||
convertSecondsToFormattedDateString,
|
||||
isANumber,
|
||||
slugifyString,
|
||||
underscorizeString,
|
||||
recursivelyChangeNullAndUndefined,
|
||||
formatDurationForDisplay,
|
||||
} from './helpers';
|
||||
|
||||
test('it can slugify a string', () => {
|
||||
|
@ -19,11 +17,6 @@ test('it can underscorize a string', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('it can keep the correct date when converting seconds to date', () => {
|
||||
const dateString = convertSecondsToFormattedDateString(1666325400);
|
||||
expect(dateString).toEqual('2022-10-21');
|
||||
});
|
||||
|
||||
test('it can validate numeric values', () => {
|
||||
expect(isANumber('11')).toEqual(true);
|
||||
expect(isANumber('hey')).toEqual(false);
|
||||
|
@ -102,13 +95,3 @@ test('it can replace null values in object with undefined', () => {
|
|||
expect(result.contacts.awesome).toEqual(false);
|
||||
expect(result.contacts.info).toEqual('');
|
||||
});
|
||||
|
||||
test('it can properly format a duration', () => {
|
||||
expect(formatDurationForDisplay(null, '0')).toEqual('0s');
|
||||
expect(formatDurationForDisplay(null, '60')).toEqual('1m');
|
||||
expect(formatDurationForDisplay(null, '65')).toEqual('1m 5s');
|
||||
expect(formatDurationForDisplay(null, 65)).toEqual('1m 5s');
|
||||
expect(formatDurationForDisplay(null, 86500)).toEqual('1d 1m 40s');
|
||||
expect(formatDurationForDisplay(null, 2629746)).toEqual('30d 10h 29m 6s');
|
||||
expect(formatDurationForDisplay(null, 31536765)).toEqual('365d 12m 45s');
|
||||
});
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import { Duration, format } from 'date-fns';
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
import {
|
||||
DATE_TIME_FORMAT,
|
||||
DATE_FORMAT,
|
||||
TIME_FORMAT_HOURS_MINUTES,
|
||||
} from './config';
|
||||
import { ProcessInstance } from './interfaces';
|
||||
|
||||
export const DEFAULT_PER_PAGE = 50;
|
||||
|
@ -87,128 +81,6 @@ export const titleizeString = (string: any) => {
|
|||
return capitalizeFirstLetter((string || '').replaceAll('_', ' '));
|
||||
};
|
||||
|
||||
export const convertDateToSeconds = (
|
||||
date: any,
|
||||
onChangeFunction: any = null
|
||||
) => {
|
||||
let dateInSeconds = date;
|
||||
if (date !== null) {
|
||||
let dateInMilliseconds = date;
|
||||
if (typeof date.getTime === 'function') {
|
||||
dateInMilliseconds = date.getTime();
|
||||
}
|
||||
dateInSeconds = Math.floor(dateInMilliseconds / 1000);
|
||||
}
|
||||
|
||||
if (onChangeFunction) {
|
||||
onChangeFunction(dateInSeconds);
|
||||
} else {
|
||||
return dateInSeconds;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertDateObjectToFormattedString = (dateObject: Date) => {
|
||||
if (dateObject) {
|
||||
return format(dateObject, DATE_FORMAT);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const dateStringToYMDFormat = (dateString: string) => {
|
||||
if (dateString && dateString.match(/^\d{2}-\d{2}-\d{4}$/)) {
|
||||
if (DATE_FORMAT.startsWith('dd')) {
|
||||
const d = dateString.split('-');
|
||||
return `${d[2]}-${d[1]}-${d[0]}`;
|
||||
}
|
||||
if (DATE_FORMAT.startsWith('MM')) {
|
||||
const d = dateString.split('-');
|
||||
return `${d[2]}-${d[0]}-${d[1]}`;
|
||||
}
|
||||
}
|
||||
return dateString;
|
||||
};
|
||||
|
||||
export const convertDateAndTimeStringsToDate = (
|
||||
dateString: string,
|
||||
timeString: string
|
||||
) => {
|
||||
if (dateString && timeString) {
|
||||
return new Date(`${dateStringToYMDFormat(dateString)}T${timeString}`);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertDateAndTimeStringsToSeconds = (
|
||||
dateString: string,
|
||||
timeString: string
|
||||
) => {
|
||||
const dateObject = convertDateAndTimeStringsToDate(dateString, timeString);
|
||||
if (dateObject) {
|
||||
return convertDateToSeconds(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertStringToDate = (dateString: string) => {
|
||||
return convertDateAndTimeStringsToDate(dateString, '00:10:00');
|
||||
};
|
||||
|
||||
export const ymdDateStringToConfiguredFormat = (dateString: string) => {
|
||||
const dateObject = convertStringToDate(dateString);
|
||||
if (dateObject) {
|
||||
return convertDateObjectToFormattedString(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertSecondsToDateObject = (seconds: number) => {
|
||||
if (seconds) {
|
||||
return new Date(seconds * 1000);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertSecondsToFormattedDateTime = (seconds: number) => {
|
||||
const dateObject = convertSecondsToDateObject(seconds);
|
||||
if (dateObject) {
|
||||
return format(dateObject, DATE_TIME_FORMAT);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertDateObjectToFormattedHoursMinutes = (dateObject: Date) => {
|
||||
if (dateObject) {
|
||||
return format(dateObject, TIME_FORMAT_HOURS_MINUTES);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertSecondsToFormattedTimeHoursMinutes = (seconds: number) => {
|
||||
const dateObject = convertSecondsToDateObject(seconds);
|
||||
if (dateObject) {
|
||||
return convertDateObjectToFormattedHoursMinutes(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertSecondsToFormattedDateString = (seconds: number) => {
|
||||
const dateObject = convertSecondsToDateObject(seconds);
|
||||
if (dateObject) {
|
||||
return convertDateObjectToFormattedString(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertDateStringToSeconds = (dateString: string) => {
|
||||
const dateObject = convertStringToDate(dateString);
|
||||
if (dateObject) {
|
||||
return convertDateToSeconds(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const objectIsEmpty = (obj: object) => {
|
||||
return Object.keys(obj).length === 0;
|
||||
};
|
||||
|
@ -368,14 +240,6 @@ export const decodeBase64 = (data: string) => {
|
|||
return Buffer.from(data, 'base64').toString('ascii');
|
||||
};
|
||||
|
||||
const MINUTES_IN_HOUR = 60;
|
||||
const SECONDS_IN_MINUTE = 60;
|
||||
const SECONDS_IN_HOUR = MINUTES_IN_HOUR * SECONDS_IN_MINUTE;
|
||||
const FOUR_HOURS_IN_SECONDS = SECONDS_IN_HOUR * 4;
|
||||
|
||||
export const REFRESH_INTERVAL_SECONDS = 5;
|
||||
export const REFRESH_TIMEOUT_SECONDS = FOUR_HOURS_IN_SECONDS;
|
||||
|
||||
export const getLastMilestoneFromProcessInstance = (
|
||||
processInstance: ProcessInstance,
|
||||
value: any
|
||||
|
@ -402,61 +266,3 @@ export const getLastMilestoneFromProcessInstance = (
|
|||
}
|
||||
return [valueToUse, truncatedValue];
|
||||
};
|
||||
|
||||
// logic from https://stackoverflow.com/a/28510323/6090676
|
||||
export const secondsToDuration = (secNum: number) => {
|
||||
const days = Math.floor(secNum / 86400);
|
||||
const hours = Math.floor(secNum / 3600) % 24;
|
||||
const minutes = Math.floor(secNum / 60) % 60;
|
||||
const seconds = secNum % 60;
|
||||
|
||||
const duration: Duration = {
|
||||
days,
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
};
|
||||
return duration;
|
||||
};
|
||||
|
||||
export const formatDurationForDisplay = (_row: any, value: any) => {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const duration = secondsToDuration(parseInt(value, 10));
|
||||
const durationTimes = [];
|
||||
if (duration.seconds !== undefined && duration.seconds > 0) {
|
||||
durationTimes.unshift(`${duration.seconds}s`);
|
||||
}
|
||||
if (duration.minutes !== undefined && duration.minutes > 0) {
|
||||
durationTimes.unshift(`${duration.minutes}m`);
|
||||
}
|
||||
if (duration.hours !== undefined && duration.hours > 0) {
|
||||
durationTimes.unshift(`${duration.hours}h`);
|
||||
}
|
||||
if (duration.days !== undefined && duration.days > 0) {
|
||||
durationTimes.unshift(`${duration.days}d`);
|
||||
}
|
||||
if (durationTimes.length < 1) {
|
||||
durationTimes.push('0s');
|
||||
}
|
||||
return durationTimes.join(' ');
|
||||
};
|
||||
|
||||
export const formatDateTime = (_row: any, value: any) => {
|
||||
if (value === undefined || value === null) {
|
||||
return value;
|
||||
}
|
||||
let dateInSeconds = value;
|
||||
if (!isANumber(value)) {
|
||||
const timeArgs = value.split('T');
|
||||
dateInSeconds = convertDateAndTimeStringsToSeconds(
|
||||
timeArgs[0],
|
||||
timeArgs[1]
|
||||
);
|
||||
}
|
||||
if (dateInSeconds) {
|
||||
return convertSecondsToFormattedDateTime(dateInSeconds);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
|
||||
import { useCallback } from 'react';
|
||||
import { DATE_FORMAT_CARBON, DATE_FORMAT_FOR_DISPLAY } from '../../../config';
|
||||
import { ymdDateStringToConfiguredFormat } from '../../../helpers';
|
||||
import DateAndTimeService from '../../../services/DateAndTimeService';
|
||||
import { getCommonAttributes } from '../../helpers';
|
||||
|
||||
/** The `BaseInputTemplate` is the template to use to render the basic `<input>` component for the `core` theme.
|
||||
|
@ -87,7 +87,7 @@ export default function BaseInputTemplate<
|
|||
dateValue = value;
|
||||
} else {
|
||||
try {
|
||||
dateValue = ymdDateStringToConfiguredFormat(value);
|
||||
dateValue = DateAndTimeService.ymdDateStringToConfiguredFormat(value);
|
||||
// let the date component and form validators handle bad dates and do not blow up
|
||||
} catch (RangeError) {}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { getTemplate, WidgetProps } from '@rjsf/utils';
|
||||
import { dateStringToYMDFormat } from '../../../helpers';
|
||||
import DateAndTimeService from '../../../services/DateAndTimeService';
|
||||
|
||||
function DateWidget(props: WidgetProps) {
|
||||
const { onChange, options, registry } = props;
|
||||
|
@ -12,7 +12,7 @@ function DateWidget(props: WidgetProps) {
|
|||
const handleChange = useCallback(
|
||||
(value: any) => {
|
||||
// react json schema forces y-m-d format for dates
|
||||
const newValue = dateStringToYMDFormat(value);
|
||||
const newValue = DateAndTimeService.dateStringToYMDFormat(value);
|
||||
onChange(newValue || undefined);
|
||||
},
|
||||
[onChange]
|
||||
|
|
|
@ -5,12 +5,8 @@ import {
|
|||
DATE_FORMAT_FOR_DISPLAY,
|
||||
DATE_RANGE_DELIMITER,
|
||||
} from '../../../config';
|
||||
import {
|
||||
convertDateObjectToFormattedString,
|
||||
convertStringToDate,
|
||||
dateStringToYMDFormat,
|
||||
} from '../../../helpers';
|
||||
import { getCommonAttributes } from '../../helpers';
|
||||
import DateAndTimeService from '../../../services/DateAndTimeService';
|
||||
|
||||
interface widgetArgs {
|
||||
id: string;
|
||||
|
@ -52,13 +48,18 @@ export default function DateRangePickerWidget({
|
|||
const onChangeLocal = useCallback(
|
||||
(dateRange: Date[]) => {
|
||||
let dateRangeString;
|
||||
const startDate = convertDateObjectToFormattedString(dateRange[0]);
|
||||
const startDate = DateAndTimeService.convertDateObjectToFormattedString(
|
||||
dateRange[0]
|
||||
);
|
||||
if (startDate) {
|
||||
const startDateYMD = dateStringToYMDFormat(startDate);
|
||||
const endDate = convertDateObjectToFormattedString(dateRange[1]);
|
||||
const startDateYMD =
|
||||
DateAndTimeService.dateStringToYMDFormat(startDate);
|
||||
const endDate = DateAndTimeService.convertDateObjectToFormattedString(
|
||||
dateRange[1]
|
||||
);
|
||||
dateRangeString = startDateYMD;
|
||||
if (endDate) {
|
||||
const endDateYMD = dateStringToYMDFormat(endDate);
|
||||
const endDateYMD = DateAndTimeService.dateStringToYMDFormat(endDate);
|
||||
dateRangeString = `${dateRangeString}${DATE_RANGE_DELIMITER}${endDateYMD}`;
|
||||
}
|
||||
}
|
||||
|
@ -73,11 +74,11 @@ export default function DateRangePickerWidget({
|
|||
let startDate = null;
|
||||
let endDate = null;
|
||||
try {
|
||||
startDate = convertStringToDate(startDateString);
|
||||
startDate = DateAndTimeService.convertStringToDate(startDateString);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (RangeError) {}
|
||||
try {
|
||||
endDate = convertStringToDate(endDateString);
|
||||
endDate = DateAndTimeService.convertStringToDate(endDateString);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (RangeError) {}
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@ import {
|
|||
getPageInfoFromSearchParams,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
refreshAtInterval,
|
||||
REFRESH_INTERVAL_SECONDS,
|
||||
REFRESH_TIMEOUT_SECONDS,
|
||||
} from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
import {
|
||||
|
@ -19,6 +17,7 @@ import {
|
|||
RecentProcessModel,
|
||||
} from '../interfaces';
|
||||
import ProcessInstanceRun from '../components/ProcessInstanceRun';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
|
||||
const PER_PAGE_FOR_TASKS_ON_HOME_PAGE = 5;
|
||||
|
||||
|
@ -47,8 +46,8 @@ export default function MyTasks() {
|
|||
|
||||
getTasks();
|
||||
refreshAtInterval(
|
||||
REFRESH_INTERVAL_SECONDS,
|
||||
REFRESH_TIMEOUT_SECONDS,
|
||||
DateAndTimeService.REFRESH_INTERVAL_SECONDS,
|
||||
DateAndTimeService.REFRESH_TIMEOUT_SECONDS,
|
||||
getTasks
|
||||
);
|
||||
}, [searchParams]);
|
||||
|
|
|
@ -45,7 +45,6 @@ import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
|||
import HttpService from '../services/HttpService';
|
||||
import ReactDiagramEditor from '../components/ReactDiagramEditor';
|
||||
import {
|
||||
convertSecondsToFormattedDateTime,
|
||||
getLastMilestoneFromProcessInstance,
|
||||
HUMAN_TASK_TYPES,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
|
@ -78,6 +77,7 @@ import {
|
|||
errorForDisplayFromString,
|
||||
} from '../components/ErrorDisplay';
|
||||
import { Notification } from '../components/Notification';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
|
||||
type OwnProps = {
|
||||
variant: string;
|
||||
|
@ -380,7 +380,9 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
<dl>
|
||||
<dt>{lastUpdatedTimeLabel}:</dt>
|
||||
<dd>
|
||||
{convertSecondsToFormattedDateTime(lastUpdatedTime || 0) || 'N/A'}
|
||||
{DateAndTimeService.convertSecondsToFormattedDateTime(
|
||||
lastUpdatedTime || 0
|
||||
) || 'N/A'}
|
||||
</dd>
|
||||
</dl>
|
||||
);
|
||||
|
@ -442,7 +444,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
<dl>
|
||||
<dt>Started:</dt>
|
||||
<dd>
|
||||
{convertSecondsToFormattedDateTime(
|
||||
{DateAndTimeService.convertSecondsToFormattedDateTime(
|
||||
processInstance.start_in_seconds || 0
|
||||
)}
|
||||
</dd>
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import DateAndTimeService from './DateAndTimeService';
|
||||
|
||||
test('it can keep the correct date when converting seconds to date', () => {
|
||||
const dateString =
|
||||
DateAndTimeService.convertSecondsToFormattedDateString(1666325400);
|
||||
expect(dateString).toEqual('2022-10-21');
|
||||
});
|
||||
test('it can properly format a duration', () => {
|
||||
expect(DateAndTimeService.formatDurationForDisplay(null, '0')).toEqual('0s');
|
||||
expect(DateAndTimeService.formatDurationForDisplay(null, '60')).toEqual('1m');
|
||||
expect(DateAndTimeService.formatDurationForDisplay(null, '65')).toEqual(
|
||||
'1m 5s'
|
||||
);
|
||||
expect(DateAndTimeService.formatDurationForDisplay(null, 65)).toEqual(
|
||||
'1m 5s'
|
||||
);
|
||||
expect(DateAndTimeService.formatDurationForDisplay(null, 86500)).toEqual(
|
||||
'1d 1m 40s'
|
||||
);
|
||||
expect(DateAndTimeService.formatDurationForDisplay(null, 2629746)).toEqual(
|
||||
'30d 10h 29m 6s'
|
||||
);
|
||||
expect(DateAndTimeService.formatDurationForDisplay(null, 31536765)).toEqual(
|
||||
'365d 12m 45s'
|
||||
);
|
||||
});
|
|
@ -0,0 +1,216 @@
|
|||
import { Duration, format } from 'date-fns';
|
||||
import {
|
||||
DATE_TIME_FORMAT,
|
||||
DATE_FORMAT,
|
||||
TIME_FORMAT_HOURS_MINUTES,
|
||||
} from '../config';
|
||||
import { isANumber } from '../helpers';
|
||||
|
||||
const MINUTES_IN_HOUR = 60;
|
||||
const SECONDS_IN_MINUTE = 60;
|
||||
const SECONDS_IN_HOUR = MINUTES_IN_HOUR * SECONDS_IN_MINUTE;
|
||||
const FOUR_HOURS_IN_SECONDS = SECONDS_IN_HOUR * 4;
|
||||
|
||||
const REFRESH_INTERVAL_SECONDS = 5;
|
||||
const REFRESH_TIMEOUT_SECONDS = FOUR_HOURS_IN_SECONDS;
|
||||
|
||||
const convertDateToSeconds = (date: any, onChangeFunction: any = null) => {
|
||||
let dateInSeconds = date;
|
||||
if (date !== null) {
|
||||
let dateInMilliseconds = date;
|
||||
if (typeof date.getTime === 'function') {
|
||||
dateInMilliseconds = date.getTime();
|
||||
}
|
||||
dateInSeconds = Math.floor(dateInMilliseconds / 1000);
|
||||
}
|
||||
|
||||
if (onChangeFunction) {
|
||||
onChangeFunction(dateInSeconds);
|
||||
} else {
|
||||
return dateInSeconds;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertDateObjectToFormattedString = (dateObject: Date) => {
|
||||
if (dateObject) {
|
||||
return format(dateObject, DATE_FORMAT);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const dateStringToYMDFormat = (dateString: string) => {
|
||||
if (dateString && dateString.match(/^\d{2}-\d{2}-\d{4}$/)) {
|
||||
if (DATE_FORMAT.startsWith('dd')) {
|
||||
const d = dateString.split('-');
|
||||
return `${d[2]}-${d[1]}-${d[0]}`;
|
||||
}
|
||||
if (DATE_FORMAT.startsWith('MM')) {
|
||||
const d = dateString.split('-');
|
||||
return `${d[2]}-${d[0]}-${d[1]}`;
|
||||
}
|
||||
}
|
||||
return dateString;
|
||||
};
|
||||
|
||||
const convertDateAndTimeStringsToDate = (
|
||||
dateString: string,
|
||||
timeString: string
|
||||
) => {
|
||||
if (dateString && timeString) {
|
||||
return new Date(`${dateStringToYMDFormat(dateString)}T${timeString}`);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertDateAndTimeStringsToSeconds = (
|
||||
dateString: string,
|
||||
timeString: string
|
||||
) => {
|
||||
const dateObject = convertDateAndTimeStringsToDate(dateString, timeString);
|
||||
if (dateObject) {
|
||||
return convertDateToSeconds(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertStringToDate = (dateString: string) => {
|
||||
return convertDateAndTimeStringsToDate(dateString, '00:10:00');
|
||||
};
|
||||
|
||||
const ymdDateStringToConfiguredFormat = (dateString: string) => {
|
||||
const dateObject = convertStringToDate(dateString);
|
||||
if (dateObject) {
|
||||
return convertDateObjectToFormattedString(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertSecondsToDateObject = (seconds: number) => {
|
||||
if (seconds) {
|
||||
return new Date(seconds * 1000);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertSecondsToFormattedDateTime = (seconds: number) => {
|
||||
const dateObject = convertSecondsToDateObject(seconds);
|
||||
if (dateObject) {
|
||||
return format(dateObject, DATE_TIME_FORMAT);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertDateObjectToFormattedHoursMinutes = (dateObject: Date) => {
|
||||
if (dateObject) {
|
||||
return format(dateObject, TIME_FORMAT_HOURS_MINUTES);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertSecondsToFormattedTimeHoursMinutes = (seconds: number) => {
|
||||
const dateObject = convertSecondsToDateObject(seconds);
|
||||
if (dateObject) {
|
||||
return convertDateObjectToFormattedHoursMinutes(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertSecondsToFormattedDateString = (seconds: number) => {
|
||||
const dateObject = convertSecondsToDateObject(seconds);
|
||||
if (dateObject) {
|
||||
return convertDateObjectToFormattedString(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const convertDateStringToSeconds = (dateString: string) => {
|
||||
const dateObject = convertStringToDate(dateString);
|
||||
if (dateObject) {
|
||||
return convertDateToSeconds(dateObject);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// logic from https://stackoverflow.com/a/28510323/6090676
|
||||
const secondsToDuration = (secNum: number) => {
|
||||
const days = Math.floor(secNum / 86400);
|
||||
const hours = Math.floor(secNum / 3600) % 24;
|
||||
const minutes = Math.floor(secNum / 60) % 60;
|
||||
const seconds = secNum % 60;
|
||||
|
||||
const duration: Duration = {
|
||||
days,
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
};
|
||||
return duration;
|
||||
};
|
||||
|
||||
const formatDurationForDisplay = (_row: any, value: any) => {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const duration = secondsToDuration(parseInt(value, 10));
|
||||
const durationTimes = [];
|
||||
if (duration.seconds !== undefined && duration.seconds > 0) {
|
||||
durationTimes.unshift(`${duration.seconds}s`);
|
||||
}
|
||||
if (duration.minutes !== undefined && duration.minutes > 0) {
|
||||
durationTimes.unshift(`${duration.minutes}m`);
|
||||
}
|
||||
if (duration.hours !== undefined && duration.hours > 0) {
|
||||
durationTimes.unshift(`${duration.hours}h`);
|
||||
}
|
||||
if (duration.days !== undefined && duration.days > 0) {
|
||||
durationTimes.unshift(`${duration.days}d`);
|
||||
}
|
||||
if (durationTimes.length < 1) {
|
||||
durationTimes.push('0s');
|
||||
}
|
||||
return durationTimes.join(' ');
|
||||
};
|
||||
|
||||
const formatDateTime = (_row: any, value: any) => {
|
||||
if (value === undefined || value === null) {
|
||||
return value;
|
||||
}
|
||||
let dateInSeconds = value;
|
||||
if (!isANumber(value)) {
|
||||
const timeArgs = value.split('T');
|
||||
dateInSeconds = convertDateAndTimeStringsToSeconds(
|
||||
timeArgs[0],
|
||||
timeArgs[1]
|
||||
);
|
||||
}
|
||||
if (dateInSeconds) {
|
||||
return convertSecondsToFormattedDateTime(dateInSeconds);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const DateAndTimeService = {
|
||||
REFRESH_INTERVAL_SECONDS,
|
||||
REFRESH_TIMEOUT_SECONDS,
|
||||
|
||||
convertDateAndTimeStringsToDate,
|
||||
convertDateAndTimeStringsToSeconds,
|
||||
convertDateObjectToFormattedHoursMinutes,
|
||||
convertDateObjectToFormattedString,
|
||||
convertDateStringToSeconds,
|
||||
convertDateToSeconds,
|
||||
convertSecondsToDateObject,
|
||||
convertSecondsToFormattedDateString,
|
||||
convertSecondsToFormattedDateTime,
|
||||
convertSecondsToFormattedTimeHoursMinutes,
|
||||
convertStringToDate,
|
||||
dateStringToYMDFormat,
|
||||
formatDateTime,
|
||||
formatDurationForDisplay,
|
||||
secondsToDuration,
|
||||
ymdDateStringToConfiguredFormat,
|
||||
};
|
||||
|
||||
export default DateAndTimeService;
|
|
@ -1,8 +1,9 @@
|
|||
import { formatDateTime, formatDurationForDisplay } from '../helpers';
|
||||
import DateAndTimeService from './DateAndTimeService';
|
||||
|
||||
const spiffFormatFunctions: { [key: string]: Function } = {
|
||||
convert_seconds_to_date_time_for_display: formatDateTime,
|
||||
convert_seconds_to_duration_for_display: formatDurationForDisplay,
|
||||
convert_seconds_to_date_time_for_display: DateAndTimeService.formatDateTime,
|
||||
convert_seconds_to_duration_for_display:
|
||||
DateAndTimeService.formatDurationForDisplay,
|
||||
};
|
||||
|
||||
const checkForSpiffFormats = (markdown: string) => {
|
||||
|
|
Loading…
Reference in New Issue