This is an automated email from the ASF dual-hosted git repository.
likyh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/main by this push:
new 7a8ac58d7 feat(config-ui): display time zone on next run time (#4596)
7a8ac58d7 is described below
commit 7a8ac58d7e754c6f07e0083072892c95544a179d
Author: 青湛 <[email protected]>
AuthorDate: Tue Mar 7 11:53:10 2023 +0800
feat(config-ui): display time zone on next run time (#4596)
Co-authored-by: Yumeng Wang <[email protected]>
---
config-ui/src/config/cron.ts | 32 ++++---
config-ui/src/images/cron-help.png | Bin 41582 -> 0 bytes
.../blueprint/components/sync-policy/index.tsx | 100 ++++++++++++---------
.../blueprint/components/sync-policy/styled.ts | 24 ++---
4 files changed, 84 insertions(+), 72 deletions(-)
diff --git a/config-ui/src/config/cron.ts b/config-ui/src/config/cron.ts
index 2648e1388..3b5f5f0b9 100644
--- a/config-ui/src/config/cron.ts
+++ b/config-ui/src/config/cron.ts
@@ -19,28 +19,31 @@
import parser from 'cron-parser';
export const cronPresets = [
- {
- label: 'Hourly',
- config: '59 * * * *',
- description: 'At minute 59 on every day-of-week from Monday through
Sunday.',
- },
{
label: 'Daily',
config: '0 0 * * *',
- description: 'At 00:00 (Midnight) on every day-of-week from Monday through
Sunday.',
+ description: '(at 00:00 AM) ',
},
{
label: 'Weekly',
config: '0 0 * * 1',
- description: 'At 00:00 (Midnight) on Monday.',
+ description: '(on Monday at 00:00 AM) ',
},
{
label: 'Monthly',
config: '0 0 1 * *',
- description: 'At 00:00 (Midnight) on day-of-month 1.',
+ description: '(on first day of the month at 00:00 AM) ',
},
];
+const getNextTime = (config: string) => {
+ try {
+ return parser.parseExpression(config, { tz: 'utc' }).next().toString();
+ } catch {
+ return null;
+ }
+};
+
export const getCron = (isManual: boolean, config: string) => {
if (isManual) {
return {
@@ -58,34 +61,37 @@ export const getCron = (isManual: boolean, config: string)
=> {
? {
...preset,
value: preset.config,
- nextTime: parser.parseExpression(preset.config).next().toString(),
+ nextTime: getNextTime(preset.config),
}
: {
label: 'Custom',
value: 'custom',
description: 'Custom',
config,
- nextTime: parser.parseExpression(config).next().toString(),
+ nextTime: getNextTime(config),
};
};
export const getCronOptions = () => {
return [
{
- label: 'Manual',
value: 'manual',
+ label: 'Manual',
+ subLabel: '',
},
]
.concat(
cronPresets.map((cp) => ({
- label: cp.label,
value: cp.config,
+ label: cp.label,
+ subLabel: cp.description,
})),
)
.concat([
{
- label: 'Custom',
value: 'custom',
+ label: 'Custom',
+ subLabel: '',
},
]);
};
diff --git a/config-ui/src/images/cron-help.png
b/config-ui/src/images/cron-help.png
deleted file mode 100644
index 8b1777c90..000000000
Binary files a/config-ui/src/images/cron-help.png and /dev/null differ
diff --git a/config-ui/src/pages/blueprint/components/sync-policy/index.tsx
b/config-ui/src/pages/blueprint/components/sync-policy/index.tsx
index bb405967e..a7d2a4e9f 100644
--- a/config-ui/src/pages/blueprint/components/sync-policy/index.tsx
+++ b/config-ui/src/pages/blueprint/components/sync-policy/index.tsx
@@ -17,11 +17,10 @@
*/
import React, { useMemo } from 'react';
-import { Checkbox, Icon, InputGroup, Position, Radio, RadioGroup } from
'@blueprintjs/core';
-import { Popover2 } from '@blueprintjs/popover2';
+import dayjs from 'dayjs';
+import { Checkbox, FormGroup, InputGroup, Radio, RadioGroup } from
'@blueprintjs/core';
import { getCron, getCronOptions } from '@/config';
-import CronHelp from '@/images/cron-help.png';
import StartFromSelector from './start-from-selector';
import * as S from './styled';
@@ -49,6 +48,7 @@ export const SyncPolicy = ({
onChangeSkipOnFail,
onChangeTimeAfter,
}: Props) => {
+ const [mintue, hour, day, month, week] = useMemo(() => cronConfig.split('
'), [cronConfig]);
const cron = useMemo(() => getCron(isManual, cronConfig), [isManual,
cronConfig]);
const options = useMemo(() => getCronOptions(), []);
@@ -75,46 +75,60 @@ export const SyncPolicy = ({
<StartFromSelector value={timeAfter} onChange={onChangeTimeAfter} />
</div>
)}
- <div className="block">
- <h3>Frequency</h3>
- <p>Blueprints will run recurringly based on the sync frequency.</p>
- <p style={{ margin: '10px 0' }}>{cron.description}</p>
- <RadioGroup selectedValue={cron.value}
onChange={handleChangeFrequency}>
- {options.map(({ label, value }) => (
- <Radio key={value} label={label} value={value} />
- ))}
- </RadioGroup>
- {cron.value === 'custom' && (
- <S.Input>
- <InputGroup value={cronConfig} onChange={(e) =>
onChangeCronConfig(e.target.value)} />
- <Popover2
- position={Position.RIGHT}
- content={
- <S.Help>
- <div className="title">
- <Icon icon="help" />
- <span>Cron Expression Format</span>
- </div>
- <p>
- Need Help? — For additional information on
<strong>Crontab</strong>, please reference the{' '}
- <a
-
href="https://man7.org/linux/man-pages/man5/crontab.5.html"
- rel="noreferrer"
- target="_blank"
- style={{ textDecoration: 'underline' }}
- >
- Crontab Linux manual
- </a>
- .
- </p>
- <img src={CronHelp} alt="" />
- </S.Help>
- }
- >
- <Icon icon="help" size={14} style={{ marginLeft: '10px',
transition: 'none' }} />
- </Popover2>
- </S.Input>
- )}
+ <div className="block" style={{ display: 'flex' }}>
+ <div className="left" style={{ flex: '0 0 500px' }}>
+ <h3>Frequency</h3>
+ <p>
+ Blueprints will run on creation and recurringly based on the
schedule. The time shown below is your LOCAL
+ time.
+ </p>
+ <RadioGroup selectedValue={cron.value}
onChange={handleChangeFrequency}>
+ {options.map(({ value, label, subLabel }) => (
+ <Radio key={value} label={`${label} ${subLabel}`} value={value}
/>
+ ))}
+ </RadioGroup>
+ {cron.value === 'custom' && (
+ <>
+ <S.Input>
+ <FormGroup label="Minute">
+ <InputGroup
+ value={mintue}
+ onChange={(e) => onChangeCronConfig([e.target.value, hour,
day, month, week].join(' '))}
+ />
+ </FormGroup>
+ <FormGroup label="Hour">
+ <InputGroup
+ value={hour}
+ onChange={(e) => onChangeCronConfig([mintue,
e.target.value, day, month, week].join(' '))}
+ />
+ </FormGroup>
+ <FormGroup label="Day">
+ <InputGroup
+ value={day}
+ onChange={(e) => onChangeCronConfig([mintue, hour,
e.target.value, month, week].join(' '))}
+ />
+ </FormGroup>
+ <FormGroup label="Month">
+ <InputGroup
+ value={month}
+ onChange={(e) => onChangeCronConfig([mintue, hour, day,
e.target.value, week].join(' '))}
+ />
+ </FormGroup>
+ <FormGroup label="Week">
+ <InputGroup
+ value={week}
+ onChange={(e) => onChangeCronConfig([mintue, hour, day,
month, e.target.value].join(' '))}
+ />
+ </FormGroup>
+ </S.Input>
+ {!cron.nextTime && <S.Error>Invalid Cron code, please enter
again.</S.Error>}
+ </>
+ )}
+ </div>
+ <div className="right">
+ <h3>Next Run Time:</h3>
+ <h4>{cron.nextTime ? dayjs(cron.nextTime).format('YYYY-MM-DD HH:mm
A') : 'N/A'}</h4>
+ </div>
</div>
<div className="block">
<h3>Running Policy</h3>
diff --git a/config-ui/src/pages/blueprint/components/sync-policy/styled.ts
b/config-ui/src/pages/blueprint/components/sync-policy/styled.ts
index cea6c13ad..41c3b55f3 100644
--- a/config-ui/src/pages/blueprint/components/sync-policy/styled.ts
+++ b/config-ui/src/pages/blueprint/components/sync-policy/styled.ts
@@ -27,28 +27,20 @@ export const Wrapper = styled.div`
export const Input = styled.div`
display: flex;
align-items: center;
-`;
-
-export const Help = styled.div`
- padding: 10px;
- width: 300px;
- font-size: 12px;
-
- .title {
- margin-bottom: 10px;
- font-size: 14px;
- font-weight: 700px;
- span.bp4-icon {
- margin-right: 4px;
- }
+ .bp4-form-group + .bp4-form-group {
+ margin-left: 8px;
}
- img {
- width: 100%;
+ .bp4-input {
+ width: 60px;
}
`;
+export const Error = styled.div`
+ color: #e34040;
+`;
+
export const FromTimeWrapper = styled.div`
.quick-selection {
margin-bottom: 16px;