mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 05:25:52 +00:00
feat(calendar): support for add/remove repeats events (#988)
* feat(calendar): support for adding repeats * feat: support delete events * fix: has many same x-action * feat: update better logic * fix: exclude is not an array * fix: handle parse cron error * feat: support every_week, every_month, every_year
This commit is contained in:
parent
30afeb0a99
commit
8f5a93bf63
@ -25,6 +25,7 @@
|
||||
"antd": "~4.19.5",
|
||||
"axios": "^0.26.1",
|
||||
"classnames": "^2.3.1",
|
||||
"cron-parser": "^4.6.0",
|
||||
"cronstrue": "^2.11.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"i18next": "^21.6.0",
|
||||
|
@ -53,6 +53,12 @@ export default {
|
||||
"Form": "Form",
|
||||
"Select data source": "Select data source",
|
||||
"Calendar": "Calendar",
|
||||
'Delete events': 'Delete events',
|
||||
'This event': 'This event',
|
||||
'This and following events': 'This and following events',
|
||||
'All events': 'All events',
|
||||
'Delete this event?': 'Delete this event?',
|
||||
'Delete Event': 'Delete Event',
|
||||
"Kanban": "Kanban",
|
||||
"Select grouping field": "Select grouping field",
|
||||
"Media": "Media",
|
||||
|
@ -54,6 +54,12 @@ export default {
|
||||
"Form": "表单",
|
||||
"Select data source": "选择数据源",
|
||||
"Calendar": "日历",
|
||||
'Delete events': '删除日程',
|
||||
'This event': '此日程',
|
||||
'This and following events': '此日程及后续日程',
|
||||
'All events': '所有日程',
|
||||
'Delete this event?': '是否删除这个日程?',
|
||||
'Delete Event': '删除日程',
|
||||
"Kanban": "看板",
|
||||
"Select grouping field": "选择分组字段",
|
||||
"Media": "多媒体",
|
||||
|
@ -7,6 +7,7 @@ import React, { useMemo, useState } from 'react';
|
||||
import { Calendar as BigCalendar, momentLocalizer } from 'react-big-calendar';
|
||||
import * as dates from 'react-big-calendar/lib/utils/dates';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { parseExpression } from 'cron-parser';
|
||||
import { RecordProvider } from '../../../';
|
||||
import { i18n } from '../../../i18n';
|
||||
import { useProps } from '../../hooks/useProps';
|
||||
@ -16,6 +17,8 @@ import { CalendarToolbarContext } from './context';
|
||||
import './style.less';
|
||||
import type { ToolbarProps } from './types';
|
||||
|
||||
const Weeks = ['month', 'week', 'day'] as const;
|
||||
|
||||
const localizer = momentLocalizer(moment);
|
||||
|
||||
function Toolbar(props: ToolbarProps) {
|
||||
@ -62,22 +65,104 @@ const messages: any = {
|
||||
showMore: (count) => i18n.t('{{count}} more items', { count }),
|
||||
};
|
||||
|
||||
const useEvents = (dataSource: any, fieldNames: any) => {
|
||||
const useEvents = (dataSource: any, fieldNames: any, date: Date, view: typeof Weeks[number]) => {
|
||||
const { t } = useTranslation();
|
||||
return useMemo(
|
||||
() =>
|
||||
Array.isArray(dataSource)
|
||||
? dataSource?.map((item) => {
|
||||
return {
|
||||
return useMemo(() => {
|
||||
if (!Array.isArray(dataSource)) return [];
|
||||
const events = [];
|
||||
|
||||
dataSource.forEach((item) => {
|
||||
const { cron, exclude = [] } = item;
|
||||
const start = moment(get(item, fieldNames.start) || moment());
|
||||
const end = moment(get(item, fieldNames.end) || start);
|
||||
const intervalTime = end.diff(start, 'millisecond', true);
|
||||
|
||||
const dateM = moment(date);
|
||||
const startDate = dateM.clone().startOf('month');
|
||||
const endDate = startDate.clone().endOf('month');
|
||||
if (view === 'month') {
|
||||
startDate.startOf('week');
|
||||
endDate.endOf('week');
|
||||
}
|
||||
const push = (fields?: Record<string, any>) => {
|
||||
// 必须在这个月的开始时间和结束时间,切在日程的开始时间之后
|
||||
const eventStart: moment.Moment = fields?.start || start;
|
||||
if (eventStart.isBefore(start) || !eventStart.isBetween(startDate, endDate)) {
|
||||
return;
|
||||
}
|
||||
const event = {
|
||||
id: get(item, fieldNames.id || 'id'),
|
||||
title: get(item, fieldNames.title) || t('Untitle'),
|
||||
start: new Date(get(item, fieldNames.start)),
|
||||
end: new Date(get(item, fieldNames.end || fieldNames.start)),
|
||||
end: eventStart.add(intervalTime, 'millisecond'),
|
||||
...fields,
|
||||
start: eventStart,
|
||||
};
|
||||
|
||||
let out = false;
|
||||
const res = exclude?.some((d) => {
|
||||
if (d.endsWith('_after')) {
|
||||
d = d.replace(/_after$/, '');
|
||||
out = true;
|
||||
return event.start.isSameOrAfter(d);
|
||||
} else {
|
||||
return event.start.isSame(d);
|
||||
}
|
||||
});
|
||||
|
||||
if (res) return out;
|
||||
events.push(event);
|
||||
};
|
||||
|
||||
if (cron === 'every_week') {
|
||||
let nextStart = start
|
||||
.clone()
|
||||
.year(startDate.year())
|
||||
.month(startDate.month())
|
||||
.date(startDate.date())
|
||||
.day(start.day());
|
||||
while (nextStart.isBefore(endDate)) {
|
||||
if (
|
||||
push({
|
||||
start: nextStart.clone(),
|
||||
})
|
||||
: [],
|
||||
[dataSource, fieldNames],
|
||||
);
|
||||
) {
|
||||
break;
|
||||
}
|
||||
nextStart.add(1, 'week');
|
||||
}
|
||||
} else if (cron === 'every_month') {
|
||||
push({
|
||||
start: start.clone().year(dateM.year()).month(dateM.month()),
|
||||
});
|
||||
} else if (cron === 'every_year') {
|
||||
push({ start: start.clone().year(dateM.year()) });
|
||||
} else {
|
||||
push();
|
||||
if (!cron) return;
|
||||
try {
|
||||
const interval = parseExpression(cron, {
|
||||
startDate: startDate.toDate(),
|
||||
endDate: endDate.toDate(),
|
||||
iterator: true,
|
||||
currentDate: start.toDate(),
|
||||
utc: true,
|
||||
});
|
||||
while (interval.hasNext()) {
|
||||
const { value } = interval.next();
|
||||
if (
|
||||
push({
|
||||
start: moment(value.toDate()),
|
||||
})
|
||||
)
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
return events;
|
||||
}, [dataSource, fieldNames, date, view]);
|
||||
};
|
||||
|
||||
const CalendarRecordViewer = (props) => {
|
||||
@ -107,21 +192,27 @@ const CalendarRecordViewer = (props) => {
|
||||
|
||||
export const Calendar: any = observer((props: any) => {
|
||||
const { dataSource, fieldNames, showLunar } = useProps(props);
|
||||
const events = useEvents(dataSource, fieldNames);
|
||||
const [date, setDate] = useState<Date>(new Date());
|
||||
const [view, setView] = useState<typeof Weeks[number]>('month');
|
||||
const events = useEvents(dataSource, fieldNames, date, view);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [record, setRecord] = useState<any>({});
|
||||
|
||||
return (
|
||||
<div {...props} style={{ height: 700 }}>
|
||||
<div style={{ height: 700 }}>
|
||||
<CalendarRecordViewer visible={visible} setVisible={setVisible} record={record} />
|
||||
<BigCalendar
|
||||
popup
|
||||
selectable
|
||||
events={events}
|
||||
views={['month', 'week', 'day']}
|
||||
view={view}
|
||||
views={Weeks}
|
||||
date={date}
|
||||
step={60}
|
||||
showMultiDayTimes
|
||||
messages={messages}
|
||||
onNavigate={setDate}
|
||||
onView={setView}
|
||||
onSelectSlot={(slotInfo) => {
|
||||
console.log('onSelectSlot', slotInfo);
|
||||
}}
|
||||
@ -133,6 +224,7 @@ export const Calendar: any = observer((props: any) => {
|
||||
if (!record) {
|
||||
return;
|
||||
}
|
||||
record.__event = event;
|
||||
setRecord(record);
|
||||
setVisible(true);
|
||||
}}
|
||||
@ -147,7 +239,6 @@ export const Calendar: any = observer((props: any) => {
|
||||
return `${local.format(start, 'Y-M', culture)} - ${local.format(end, 'Y-M', culture)}`;
|
||||
},
|
||||
}}
|
||||
defaultDate={new Date()}
|
||||
components={{
|
||||
toolbar: (props) => <Toolbar {...props} showLunar={showLunar}></Toolbar>,
|
||||
week: {
|
||||
|
@ -0,0 +1,66 @@
|
||||
import { observer } from '@formily/react';
|
||||
import { Modal, Radio, Space, Typography } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useBlockRequestContext, useFilterByTk } from '../../../block-provider';
|
||||
import { useRecord } from '../../../record-provider';
|
||||
import { useActionContext } from '../action';
|
||||
const { Text } = Typography;
|
||||
|
||||
export const DeleteEvent = observer(() => {
|
||||
const { visible, setVisible } = useActionContext();
|
||||
const { exclude = [], cron, ...record } = useRecord();
|
||||
const startDate = record.__parent.__event.start.format();
|
||||
const filterByTk = useFilterByTk();
|
||||
const { resource, service, __parent } = useBlockRequestContext();
|
||||
const [value, onChange] = useState(startDate);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const onOk = async () => {
|
||||
setLoading(true);
|
||||
if (value === 'all' || !cron) {
|
||||
await resource.destroy({
|
||||
filterByTk,
|
||||
});
|
||||
} else {
|
||||
await resource.update({
|
||||
filterByTk,
|
||||
values: {
|
||||
exclude: (exclude || []).concat(value),
|
||||
},
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
__parent?.service?.refresh?.();
|
||||
service?.refresh?.();
|
||||
setVisible?.(false, true);
|
||||
};
|
||||
|
||||
const { t } = useTranslation();
|
||||
return createPortal(
|
||||
<Modal
|
||||
title={cron ? t('Delete events') : null}
|
||||
visible={visible}
|
||||
onCancel={() => setVisible(false)}
|
||||
onOk={() => onOk()}
|
||||
confirmLoading={loading}
|
||||
>
|
||||
{cron ? (
|
||||
<Radio.Group value={value} onChange={(event) => onChange(event.target.value)}>
|
||||
<Space direction="vertical">
|
||||
<Radio value={startDate}>{t('This event')}</Radio>
|
||||
<Radio value={`${startDate}_after`}>{t('This and following events')}</Radio>
|
||||
<Radio value="all">{t('All events')}</Radio>
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
) : (
|
||||
<Text strong style={{ fontSize: '18px' }}>
|
||||
{t('Delete this event?')}
|
||||
</Text>
|
||||
)}
|
||||
</Modal>,
|
||||
document.body,
|
||||
);
|
||||
});
|
||||
|
||||
export default DeleteEvent;
|
@ -1,3 +1,4 @@
|
||||
import DeleteEvent from './DeleteEvent';
|
||||
import { ActionBar } from '../action';
|
||||
import { Calendar } from './Calendar';
|
||||
import { CalendarDesigner } from './Calendar.Designer';
|
||||
@ -10,6 +11,7 @@ import { ViewSelect } from './ViewSelect';
|
||||
|
||||
Calendar.ActionBar = ActionBar;
|
||||
Calendar.Event = Event;
|
||||
Calendar.DeleteEvent = DeleteEvent;
|
||||
Calendar.Title = Title;
|
||||
Calendar.Today = Today;
|
||||
Calendar.Nav = Nav;
|
||||
|
@ -0,0 +1,160 @@
|
||||
// 表单的操作配置
|
||||
export const CalendarFormActionInitializers = {
|
||||
title: '{{t("Configure actions")}}',
|
||||
icon: 'SettingOutlined',
|
||||
style: {
|
||||
marginLeft: 8,
|
||||
},
|
||||
items: [
|
||||
{
|
||||
type: 'itemGroup',
|
||||
title: '{{t("Enable actions")}}',
|
||||
children: [
|
||||
{
|
||||
type: 'item',
|
||||
title: '{{t("Edit")}}',
|
||||
component: 'UpdateActionInitializer',
|
||||
schema: {
|
||||
'x-component': 'Action',
|
||||
'x-decorator': 'ACLActionProvider',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
title: '{{t("Delete")}}',
|
||||
component: 'DestroyActionInitializer',
|
||||
schema: {
|
||||
'x-component': 'Action',
|
||||
'x-decorator': 'ACLActionProvider',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
title: '{{t("Delete Event")}}',
|
||||
component: 'DeleteEventActionInitializer',
|
||||
schema: {
|
||||
'x-component': 'Action',
|
||||
'x-decorator': 'ACLActionProvider',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
title: '{{t("Print")}}',
|
||||
component: 'PrintActionInitializer',
|
||||
schema: {
|
||||
'x-component': 'Action',
|
||||
'x-decorator': 'ACLActionProvider',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
type: 'subMenu',
|
||||
title: '{{t("Customize")}}',
|
||||
children: [
|
||||
{
|
||||
type: 'item',
|
||||
title: '{{t("Popup")}}',
|
||||
component: 'CustomizeActionInitializer',
|
||||
schema: {
|
||||
type: 'void',
|
||||
title: '{{ t("Popup") }}',
|
||||
'x-action': 'customize:popup',
|
||||
'x-designer': 'Action.Designer',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
openMode: 'drawer',
|
||||
},
|
||||
properties: {
|
||||
drawer: {
|
||||
type: 'void',
|
||||
title: '{{ t("Popup") }}',
|
||||
'x-component': 'Action.Container',
|
||||
'x-component-props': {
|
||||
className: 'nb-action-popup',
|
||||
},
|
||||
properties: {
|
||||
tabs: {
|
||||
type: 'void',
|
||||
'x-component': 'Tabs',
|
||||
'x-component-props': {},
|
||||
'x-initializer': 'TabPaneInitializers',
|
||||
properties: {
|
||||
tab1: {
|
||||
type: 'void',
|
||||
title: '{{t("Details")}}',
|
||||
'x-component': 'Tabs.TabPane',
|
||||
'x-designer': 'Tabs.Designer',
|
||||
'x-component-props': {},
|
||||
properties: {
|
||||
grid: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid',
|
||||
'x-initializer': 'RecordBlockInitializers',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
title: '{{t("Update record")}}',
|
||||
component: 'CustomizeActionInitializer',
|
||||
schema: {
|
||||
title: '{{ t("Update record") }}',
|
||||
'x-component': 'Action',
|
||||
'x-designer': 'Action.Designer',
|
||||
'x-action': 'customize:update',
|
||||
'x-action-settings': {
|
||||
assignedValues: {},
|
||||
onSuccess: {
|
||||
manualClose: true,
|
||||
redirecting: false,
|
||||
successMessage: '{{t("Updated successfully")}}',
|
||||
},
|
||||
},
|
||||
'x-component-props': {
|
||||
useProps: '{{ useCustomizeUpdateActionProps }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
title: '{{t("Custom request")}}',
|
||||
component: 'CustomizeActionInitializer',
|
||||
schema: {
|
||||
title: '{{ t("Custom request") }}',
|
||||
'x-component': 'Action',
|
||||
'x-action': 'customize:form:request',
|
||||
'x-designer': 'Action.Designer',
|
||||
'x-action-settings': {
|
||||
requestSettings: {},
|
||||
skipValidator: false,
|
||||
onSuccess: {
|
||||
manualClose: false,
|
||||
redirecting: false,
|
||||
successMessage: '{{t("Request success")}}',
|
||||
},
|
||||
},
|
||||
'x-component-props': {
|
||||
useProps: '{{ useCustomizeRequestActionProps }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
@ -12,7 +12,7 @@ const recursiveParent = (schema: Schema) => {
|
||||
} else {
|
||||
return recursiveParent(schema.parent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const useRelationFields = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
@ -52,7 +52,7 @@ const useRelationFields = () => {
|
||||
// component: 'RecordAssociationFormBlockInitializer',
|
||||
// },
|
||||
],
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (['hasMany', 'belongsToMany'].includes(field.type)) {
|
||||
@ -90,7 +90,7 @@ const useRelationFields = () => {
|
||||
component: 'RecordAssociationCalendarBlockInitializer',
|
||||
},
|
||||
],
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
@ -124,6 +124,7 @@ export const RecordBlockInitializers = (props: any) => {
|
||||
type: 'item',
|
||||
title: '{{t("Details")}}',
|
||||
component: 'RecordReadPrettyFormBlockInitializer',
|
||||
actionInitializers: 'CalendarFormActionInitializers',
|
||||
},
|
||||
{
|
||||
key: 'form',
|
||||
|
@ -9,6 +9,7 @@ export * from './FormActionInitializers';
|
||||
export * from './FormItemInitializers';
|
||||
export * from './KanbanActionInitializers';
|
||||
export * from './ReadPrettyFormActionInitializers';
|
||||
export * from './CalendarFormActionInitializers';
|
||||
export * from './ReadPrettyFormItemInitializers';
|
||||
export * from './RecordBlockInitializers';
|
||||
export * from './RecordFormBlockInitializers';
|
||||
@ -18,4 +19,3 @@ export * from './TableActionInitializers';
|
||||
export * from './TableColumnInitializers';
|
||||
export * from './TableSelectorInitializers';
|
||||
export * from './TabPaneInitializers';
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
import { ActionInitializer } from './ActionInitializer';
|
||||
|
||||
export const DeleteEventActionInitializer = (props) => {
|
||||
const schema = {
|
||||
title: '{{ t("Delete Event") }}',
|
||||
'x-action': 'deleteEvent',
|
||||
'x-component': 'Action',
|
||||
'x-designer': 'Action.Designer',
|
||||
'x-component-props': {
|
||||
icon: 'DeleteOutlined',
|
||||
},
|
||||
properties: {
|
||||
modal: {
|
||||
'x-component': 'CalendarV2.DeleteEvent',
|
||||
},
|
||||
},
|
||||
};
|
||||
return <ActionInitializer {...props} schema={schema} />;
|
||||
};
|
@ -1,10 +1,10 @@
|
||||
import React from "react";
|
||||
import React from 'react';
|
||||
import { FormOutlined } from '@ant-design/icons';
|
||||
import { useBlockAssociationContext, useBlockRequestContext } from "../../block-provider";
|
||||
import { useCollection } from "../../collection-manager";
|
||||
import { useSchemaTemplateManager } from "../../schema-templates";
|
||||
import { SchemaInitializer } from "../SchemaInitializer";
|
||||
import { createReadPrettyFormBlockSchema, useRecordCollectionDataSourceItems } from "../utils";
|
||||
import { useBlockAssociationContext, useBlockRequestContext } from '../../block-provider';
|
||||
import { useCollection } from '../../collection-manager';
|
||||
import { useSchemaTemplateManager } from '../../schema-templates';
|
||||
import { SchemaInitializer } from '../SchemaInitializer';
|
||||
import { createReadPrettyFormBlockSchema, useRecordCollectionDataSourceItems } from '../utils';
|
||||
|
||||
export const RecordReadPrettyFormBlockInitializer = (props) => {
|
||||
const { onCreateBlockSchema, componentType, createBlockSchema, insert, ...others } = props;
|
||||
@ -13,7 +13,8 @@ export const RecordReadPrettyFormBlockInitializer = (props) => {
|
||||
const collection = useCollection();
|
||||
const association = useBlockAssociationContext();
|
||||
const { block } = useBlockRequestContext();
|
||||
const actionInitializers = block !== 'TableField' ? 'ReadPrettyFormActionInitializers' : null;
|
||||
const actionInitializers =
|
||||
block !== 'TableField' ? props.actionInitializers || 'ReadPrettyFormActionInitializers' : null;
|
||||
|
||||
return (
|
||||
<SchemaInitializer.Item
|
||||
@ -56,4 +57,4 @@ export const RecordReadPrettyFormBlockInitializer = (props) => {
|
||||
items={useRecordCollectionDataSourceItems('ReadPrettyFormItem')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
@ -12,6 +12,7 @@ export * from './CustomizeActionInitializer';
|
||||
export * from './CustomizeBulkEditActionInitializer';
|
||||
export * from './DataBlockInitializer';
|
||||
export * from './DestroyActionInitializer';
|
||||
export * from './DeleteEventActionInitializer';
|
||||
export * from './DetailsBlockInitializer';
|
||||
export * from './FilterActionInitializer';
|
||||
export * from './FormBlockInitializer';
|
||||
@ -36,4 +37,3 @@ export * from './TableSelectorInitializer';
|
||||
export * from './UpdateActionInitializer';
|
||||
export * from './UpdateSubmitActionInitializer';
|
||||
export * from './ViewActionInitializer';
|
||||
|
||||
|
32
yarn.lock
32
yarn.lock
@ -5352,7 +5352,14 @@
|
||||
resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
|
||||
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
|
||||
|
||||
"@types/react-dom@^16.9.8", "@types/react-dom@^17.0.0":
|
||||
"@types/react-dom@^16.9.8":
|
||||
version "16.9.17"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.17.tgz#29100cbcc422d7b7dba7de24bb906de56680dd34"
|
||||
integrity sha512-qSRyxEsrm5btPXnowDOs5jSkgT8ldAA0j6Qp+otHUh+xHzy3sXmgNfyhucZjAjkgpdAUw9rJe0QRtX/l+yaS4g==
|
||||
dependencies:
|
||||
"@types/react" "^16"
|
||||
|
||||
"@types/react-dom@^17.0.0":
|
||||
version "17.0.11"
|
||||
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466"
|
||||
integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==
|
||||
@ -5412,7 +5419,7 @@
|
||||
"@types/history" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@>=16.9.11", "@types/react@^16.9.43", "@types/react@^17.0.0":
|
||||
"@types/react@*", "@types/react@>=16.9.11", "@types/react@^17.0.0":
|
||||
version "17.0.34"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.34.tgz#797b66d359b692e3f19991b6b07e4b0c706c0102"
|
||||
integrity sha512-46FEGrMjc2+8XhHXILr+3+/sTe3OfzSPU9YGKILLrUYbQ1CLQC9Daqo1KzENGXAWwrFwiY0l4ZbF20gRvgpWTg==
|
||||
@ -5421,6 +5428,15 @@
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/react@^16", "@types/react@^16.9.43":
|
||||
version "16.14.34"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.34.tgz#d129324ffda312044e1c47aab18696e4ed493282"
|
||||
integrity sha512-b99nWeGGReLh6aKBppghVqp93dFJtgtDOzc8NXM6hewD8PQ2zZG5kBLgbx+VJr7Q7WBMjHxaIl3dwpwwPIUgyA==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/resolve@1.17.1":
|
||||
version "1.17.1"
|
||||
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
|
||||
@ -8718,6 +8734,13 @@ cron-parser@4.4.0:
|
||||
dependencies:
|
||||
luxon "^1.28.0"
|
||||
|
||||
cron-parser@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.6.0.tgz#404c3fdbff10ae80eef6b709555d577ef2fd2e0d"
|
||||
integrity sha512-guZNLMGUgg6z4+eGhmHGw7ft+v6OQeuHzd1gcLxCo9Yg/qoxmG3nindp2/uwGCLizEisf2H0ptqeVXeoCpP6FA==
|
||||
dependencies:
|
||||
luxon "^3.0.1"
|
||||
|
||||
croner@~4.1.92:
|
||||
version "4.1.97"
|
||||
resolved "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz#6e373dc7bb3026fab2deb0d82685feef20796766"
|
||||
@ -14872,6 +14895,11 @@ luxon@^1.28.0:
|
||||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.28.0.tgz#e7f96daad3938c06a62de0fb027115d251251fbf"
|
||||
integrity sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==
|
||||
|
||||
luxon@^3.0.1:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.0.4.tgz#d179e4e9f05e092241e7044f64aaa54796b03929"
|
||||
integrity sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==
|
||||
|
||||
lz-string@^1.4.4:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
|
||||
|
Loading…
Reference in New Issue
Block a user