Web:Component:Cron Added a method for getting the time of the next synchronization
This commit is contained in:
parent
9b1f7d3f8e
commit
3e4a1a5ae1
@ -1,6 +1,8 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import i18n from "i18next";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import i18n from "i18next";
|
||||
|
||||
import Cron, { getNextSynchronization } from ".";
|
||||
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
@ -53,8 +55,6 @@ i18n.use(initReactI18next).init({
|
||||
},
|
||||
});
|
||||
|
||||
import Cron from ".";
|
||||
|
||||
type CronType = typeof Cron;
|
||||
|
||||
type Story = StoryObj<CronType>;
|
||||
@ -88,9 +88,14 @@ export const Default: Story = {
|
||||
setValue(defaultValue);
|
||||
}, [defaultValue]);
|
||||
|
||||
const date = useMemo(() => cron && getNextSynchronization(cron), [cron]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input
|
||||
style={{
|
||||
borderColor: error ? "red" : "black",
|
||||
}}
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
onBlur={(e) => setCron(e.target.value)}
|
||||
@ -102,6 +107,12 @@ export const Default: Story = {
|
||||
<p>
|
||||
<strong>Error message: </strong> {error?.message ?? "undefined"}
|
||||
</p>
|
||||
{date && (
|
||||
<p>
|
||||
<strong>Next synchronization: </strong>{" "}
|
||||
{date.toUTC().setLocale("en-GB").toFormat("DDDD tt")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
@ -1 +1,2 @@
|
||||
export { default } from "./Cron";
|
||||
export { getNextSynchronization } from "./part";
|
||||
|
@ -1,8 +1,14 @@
|
||||
import { DateTime } from "luxon";
|
||||
import { Options, PeriodType } from "./types";
|
||||
import { defaultOptions, units } from "./constants";
|
||||
import { arrayToStringPart, assertValidArray, stringToArrayPart } from "./util";
|
||||
import {
|
||||
arrayToStringPart,
|
||||
assertValidArray,
|
||||
findDate,
|
||||
stringToArrayPart,
|
||||
} from "./util";
|
||||
|
||||
export const stringToArray = (str: string) => {
|
||||
export const stringToArray = (str: string, full = false) => {
|
||||
if (typeof str !== "string") {
|
||||
throw new Error("Invalid cron string");
|
||||
}
|
||||
@ -10,7 +16,7 @@ export const stringToArray = (str: string) => {
|
||||
if (parts.length !== 5) {
|
||||
throw new Error("Invalid cron string format");
|
||||
} else {
|
||||
return parts.map((str, idx) => stringToArrayPart(str, units[idx]));
|
||||
return parts.map((str, idx) => stringToArrayPart(str, units[idx], full));
|
||||
}
|
||||
};
|
||||
|
||||
@ -51,3 +57,25 @@ export function getCronStringFromValues(
|
||||
|
||||
return parsedArray;
|
||||
}
|
||||
|
||||
export const getNextSynchronization = (
|
||||
cronString: string,
|
||||
timezone?: string
|
||||
) => {
|
||||
const cron = stringToArray(cronString, true);
|
||||
assertValidArray(cron);
|
||||
let date = DateTime.now();
|
||||
|
||||
if (timezone) date = date.setZone(timezone);
|
||||
|
||||
if (!date.isValid) {
|
||||
throw new Error("Invalid timezone provided");
|
||||
}
|
||||
|
||||
if (date.second > 0) {
|
||||
// plus a minute to the date to prevent returning dates in the past
|
||||
date = date.plus({ minute: 1 });
|
||||
}
|
||||
|
||||
return findDate(cron, date);
|
||||
};
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { DateTime } from "luxon";
|
||||
import { Options, PeriodType, Unit } from "./types";
|
||||
|
||||
export const parseNumber = (value: unknown) => {
|
||||
@ -17,7 +18,7 @@ export const parseNumber = (value: unknown) => {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const assertValidArray = (arr: unknown) => {
|
||||
export const assertValidArray = (arr: unknown): void | never => {
|
||||
if (
|
||||
arr === undefined ||
|
||||
!Array.isArray(arr) ||
|
||||
@ -100,8 +101,8 @@ export const arrayToStringPart = (
|
||||
return toString(values, unit, options);
|
||||
};
|
||||
|
||||
export const stringToArrayPart = (str: string, unit: Unit) => {
|
||||
if (str === "*" || str === "*/1") {
|
||||
export const stringToArrayPart = (str: string, unit: Unit, full = false) => {
|
||||
if ((str === "*" || str === "*/1") && !full) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@ -332,3 +333,72 @@ const getStep = (values: number[]) => {
|
||||
const isFull = (values: number[], unit: Unit) => {
|
||||
return values.length === unit.max - unit.min + 1;
|
||||
};
|
||||
|
||||
const shiftMonth = (arr: number[][], date: DateTime) => {
|
||||
while (arr[3].indexOf(date.month) === -1) {
|
||||
date = date.plus({ months: 1 }).startOf("month");
|
||||
}
|
||||
return date;
|
||||
};
|
||||
|
||||
const shiftDay = (arr: number[][], date: DateTime): [DateTime, boolean] => {
|
||||
const currentMonth = date.month;
|
||||
while (
|
||||
arr[2].indexOf(date.day) === -1 ||
|
||||
// luxon uses 1-7 for weekdays, but we use 0-6
|
||||
arr[4].indexOf(date.weekday === 7 ? 0 : date.weekday) === -1
|
||||
) {
|
||||
date = date.plus({ days: 1 }).startOf("day");
|
||||
if (currentMonth !== date.month) {
|
||||
return [date, true];
|
||||
}
|
||||
}
|
||||
return [date, false];
|
||||
};
|
||||
|
||||
const shiftHour = (arr: number[][], date: DateTime): [DateTime, boolean] => {
|
||||
const currentDay = date.day;
|
||||
while (arr[1].indexOf(date.hour) === -1) {
|
||||
date = date.plus({ hours: 1 }).startOf("hour");
|
||||
if (currentDay !== date.day) {
|
||||
return [date, true];
|
||||
}
|
||||
}
|
||||
return [date, false];
|
||||
};
|
||||
|
||||
const shiftMinute = (arr: number[][], date: DateTime): [DateTime, boolean] => {
|
||||
const currentHour = date.hour;
|
||||
while (arr[0].indexOf(date.minute) === -1) {
|
||||
date = date.plus({ minutes: 1 }).startOf("minute");
|
||||
if (currentHour !== date.hour) {
|
||||
return [date, true];
|
||||
}
|
||||
}
|
||||
return [date, false];
|
||||
};
|
||||
|
||||
export const findDate = (arr: number[][], date: DateTime) => {
|
||||
let retry = 24;
|
||||
let monthChanged: boolean;
|
||||
let dayChanged: boolean;
|
||||
let hourChanged: boolean;
|
||||
|
||||
while (--retry) {
|
||||
date = shiftMonth(arr, date);
|
||||
[date, monthChanged] = shiftDay(arr, date);
|
||||
if (!monthChanged) {
|
||||
[date, dayChanged] = shiftHour(arr, date);
|
||||
if (!dayChanged) {
|
||||
[date, hourChanged] = shiftMinute(arr, date);
|
||||
if (!hourChanged) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!retry) {
|
||||
throw new Error("Unable to find execution time for schedule");
|
||||
}
|
||||
return date.set({ second: 0, millisecond: 0 });
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user