diff --git a/package.json b/package.json
index fd68db12..24d5ef0f 100644
--- a/package.json
+++ b/package.json
@@ -36,9 +36,11 @@
"@fontsource/roboto": "^5.0.8",
"@mui/icons-material": "^5.14.16",
"@mui/material": "^5.14.16",
+ "@mui/x-date-pickers": "^6.18.0",
"@vitejs/plugin-react-swc": "^3.4.1",
"apollo-upload-client": "^17.0.0",
"axios": "^1.6.0",
+ "dayjs": "^1.11.10",
"file-selector": "^0.6.0",
"graphql-tag": "^2.12.6",
"graphql-ws": "^5.14.2",
diff --git a/src/components/settings/NumberSetting.tsx b/src/components/settings/NumberSetting.tsx
index 96248e30..1e702d43 100644
--- a/src/components/settings/NumberSetting.tsx
+++ b/src/components/settings/NumberSetting.tsx
@@ -22,7 +22,7 @@ import Slider from '@mui/material/Slider';
type BaseProps = {
settingTitle: string;
- settingValue: string;
+ settingValue?: string;
settingIcon?: React.ReactNode;
value: number;
defaultValue?: number;
@@ -98,7 +98,7 @@ export const NumberSetting = ({
{settingIcon ? {settingIcon} : null}
diff --git a/src/components/settings/TimeSetting.tsx b/src/components/settings/TimeSetting.tsx
new file mode 100644
index 00000000..1d17b9a6
--- /dev/null
+++ b/src/components/settings/TimeSetting.tsx
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) Contributors to the Suwayomi project
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+import { Button, Dialog, DialogTitle, ListItemText } from '@mui/material';
+import DialogContent from '@mui/material/DialogContent';
+import DialogActions from '@mui/material/DialogActions';
+import ListItemButton from '@mui/material/ListItemButton';
+import { useCallback, useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { TimePicker } from '@mui/x-date-pickers/TimePicker';
+import dayjs from 'dayjs';
+import { loadDayJsLocale } from '@/util/language.tsx';
+
+export const TimeSetting = ({
+ settingName,
+ value,
+ defaultValue,
+ handleChange,
+}: {
+ settingName: string;
+ value?: string;
+ defaultValue: string;
+ handleChange: (path: string) => void;
+}) => {
+ const { t, i18n } = useTranslation();
+
+ const [isDialogOpen, setIsDialogOpen] = useState(false);
+ const [dialogValue, setDialogValue] = useState(value ?? defaultValue);
+
+ const [locale, setLocale] = useState('en');
+
+ const currentLocale = i18n.language;
+
+ useEffect(() => {
+ loadDayJsLocale(currentLocale).then((wasLoaded) => setLocale(wasLoaded ? currentLocale : 'en'));
+ }, [currentLocale]);
+
+ useEffect(() => {
+ if (!value) {
+ return;
+ }
+
+ setDialogValue(value);
+ }, [value]);
+
+ const closeDialog = useCallback(
+ (resetValue: boolean) => {
+ setIsDialogOpen(false);
+
+ if (resetValue) {
+ setDialogValue(value ?? defaultValue);
+ }
+ },
+ [value],
+ );
+
+ const closeDialogWithReset = useCallback(() => closeDialog(true), [closeDialog]);
+
+ const updateSetting = useCallback(
+ (newValue: string, shouldCloseDialog: boolean = true) => {
+ if (shouldCloseDialog) {
+ closeDialog(false);
+ }
+
+ const didValueChange = value !== newValue;
+ if (!didValueChange) {
+ return;
+ }
+
+ handleChange(newValue);
+ },
+ [value, handleChange, closeDialog],
+ );
+
+ return (
+ <>
+ setIsDialogOpen(true)}>
+
+
+
+
+ >
+ );
+};
diff --git a/src/components/settings/downloads/DownloadAheadSetting.tsx b/src/components/settings/downloads/DownloadAheadSetting.tsx
index 0bb460aa..679bf619 100644
--- a/src/components/settings/downloads/DownloadAheadSetting.tsx
+++ b/src/components/settings/downloads/DownloadAheadSetting.tsx
@@ -21,7 +21,7 @@ export const DownloadAheadSetting = () => {
const { t } = useTranslation();
const { data } = requestManager.useGetServerSettings();
- const downloadAheadLimit = data?.settings.autoDownloadAheadLimit ?? 0;
+ const downloadAheadLimit = data?.settings.autoDownloadAheadLimit;
const shouldDownloadAhead = !!downloadAheadLimit;
const [mutateSettings] = requestManager.useUpdateServerSettings();
@@ -49,10 +49,14 @@ export const DownloadAheadSetting = () => {
{shouldDownloadAhead ? (
{
const { t } = useTranslation();
const { data } = requestManager.useGetServerSettings();
- const autoUpdateIntervalHours = data?.settings.globalUpdateInterval ?? 0;
+ const autoUpdateIntervalHours = data?.settings.globalUpdateInterval;
const doAutoUpdates = !!autoUpdateIntervalHours;
const [mutateSettings] = requestManager.useUpdateServerSettings();
@@ -45,9 +45,13 @@ export const GlobalUpdateSettingsInterval = () => {
{doAutoUpdates ? (
{
+ switch (format) {
+ case 'lowercase':
+ return value.toLowerCase();
+ default:
+ return value;
+ }
+ },
},
returnNull: false,
debug: process.env.NODE_ENV !== 'production',
diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json
index b1ac893d..1d72108d 100644
--- a/src/i18n/locale/en.json
+++ b/src/i18n/locale/en.json
@@ -243,10 +243,18 @@
},
"date": {
"label": {
+ "day": "Day",
+ "day_one": "Day",
+ "day_other": "Days",
"today": "Today",
"today_at": "Today at {{timeString}}",
"yesterday": "Yesterday",
"yesterday_at": "Yesterday at {{timeString}}"
+ },
+ "value": {
+ "label": {
+ "day": "{{days}} $t(global.date.label.day, lowercase)"
+ }
}
},
"error": {
@@ -278,6 +286,7 @@
"display": "Display",
"filter": "Filter",
"loading": "Loading…",
+ "never": "Never",
"none": "None",
"sort": "Sort",
"unknown": "Unknown"
@@ -486,6 +495,24 @@
"title": "About"
},
"backup": {
+ "automated": {
+ "cleanup": {
+ "label": {
+ "title": "Backup cleanup",
+ "value": "Delete backups that are older than $t(global.date.value.label.day)"
+ }
+ },
+ "label": {
+ "interval": "Backup interval",
+ "time": "Backup time"
+ },
+ "location": {
+ "label": {
+ "description": "The path to the directory on the server where automated backups should get saved in",
+ "title": "Backup location"
+ }
+ }
+ },
"label": {
"backup_restore_failed": "Could not restore backup",
"create_backup": "Create backup",
diff --git a/src/screens/settings/Backup.tsx b/src/screens/settings/Backup.tsx
index 44426c67..c0b93392 100644
--- a/src/screens/settings/Backup.tsx
+++ b/src/screens/settings/Backup.tsx
@@ -13,12 +13,39 @@ import { fromEvent } from 'file-selector';
import { useTranslation } from 'react-i18next';
import { ListItemButton } from '@mui/material';
import ListItemIcon from '@mui/material/ListItemIcon';
+import ListSubheader from '@mui/material/ListSubheader';
+import { t as translate } from 'i18next';
import { requestManager } from '@/lib/requests/RequestManager.ts';
import { makeToast } from '@/components/util/Toast';
import { ListItemLink } from '@/components/util/ListItemLink';
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext';
import { BackupRestoreState } from '@/lib/graphql/generated/graphql.ts';
import { Progress } from '@/components/util/Progress.tsx';
+import { ServerDirSetting } from '@/components/settings/ServerDirSetting.tsx';
+import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
+import { TimeSetting } from '@/components/settings/TimeSetting.tsx';
+import { ServerSettings } from '@/typings.ts';
+
+type BackupSettingsType = Pick;
+
+const extractBackupSettings = (settings: ServerSettings): BackupSettingsType => ({
+ backupPath: settings.backupPath,
+ backupTime: settings.backupTime,
+ backupInterval: settings.backupInterval,
+ backupTTL: settings.backupTTL,
+});
+
+const getBackupCleanupDisplayValue = (ttl?: number) => {
+ if (ttl === undefined) {
+ return undefined;
+ }
+
+ if (ttl === 0) {
+ return translate('global.label.never');
+ }
+
+ return translate('settings.backup.automated.cleanup.label.value', { days: ttl, count: ttl });
+};
let backupRestoreId: string | undefined;
@@ -32,6 +59,11 @@ export function Backup() {
useSetDefaultBackTo('settings');
+ const { data: settingsData } = requestManager.useGetServerSettings();
+ const [mutateSettings] = requestManager.useUpdateServerSettings();
+
+ const backupSettings = settingsData ? extractBackupSettings(settingsData.settings) : undefined;
+
const { data } = requestManager.useGetBackupRestoreStatus(backupRestoreId ?? '', {
skip: !backupRestoreId,
pollInterval: 1000,
@@ -48,6 +80,13 @@ export function Backup() {
return Number.isNaN(progress) ? 0 : progress;
})();
+ const updateSetting = (
+ setting: Setting,
+ value: BackupSettingsType[Setting],
+ ) => {
+ mutateSettings({ variables: { input: { settings: { [setting]: value } } } });
+ };
+
useEffect(() => {
if (!data?.restoreStatus) {
return;
@@ -142,6 +181,59 @@ export function Backup() {
) : null}
+
+ Automated backup
+
+ }
+ >
+ updateSetting('backupPath', path)}
+ />
+ updateSetting('backupTime', time)}
+ />
+ updateSetting('backupInterval', interval)}
+ />
+ updateSetting('backupTTL', ttl)}
+ />
+
>
diff --git a/src/util/language.tsx b/src/util/language.tsx
index 066cc579..45af69ae 100644
--- a/src/util/language.tsx
+++ b/src/util/language.tsx
@@ -14,67 +14,88 @@ export enum DefaultLanguage {
LOCAL_SOURCE = 'localsourcelang',
}
+const loadDefaultDayJsLocale = () => import('dayjs/locale/en.js');
+
export const ISOLanguages = [
// full list: https://github.com/meikidd/iso-639-1/blob/master/src/data.js
- { code: 'en', name: 'English', nativeName: 'English' },
- { code: 'ca', name: 'Catalan; Valencian', nativeName: 'Català' },
- { code: 'de', name: 'German', nativeName: 'Deutsch' },
- { code: 'es', name: 'Spanish; Castilian', nativeName: 'Español' },
- { code: 'es-419', name: 'Spanish; Castilian', nativeName: 'Español (Latinoamérica)' },
- { code: 'fr', name: 'French', nativeName: 'Français' },
- { code: 'id', name: 'Indonesian', nativeName: 'Indonesia' },
- { code: 'it', name: 'Italian', nativeName: 'Italiano' },
- { code: 'pt', name: 'Portuguese', nativeName: 'Português' },
- { code: 'pt-pt', name: 'Portuguese', nativeName: 'Português (Portugal)' },
- { code: 'pt-br', name: 'Portuguese; Brasil', nativeName: 'Português (Brasil)' },
- { code: 'vi', name: 'Vietnamese', nativeName: 'Tiếng Việt' },
- { code: 'tr', name: 'Turkish', nativeName: 'Türkçe' },
- { code: 'ru', name: 'Russian', nativeName: 'русский' },
- { code: 'ar', name: 'Arabic', nativeName: 'العربية' },
- { code: 'hi', name: 'Hindi', nativeName: 'हिन्दी' },
- { code: 'th', name: 'Thai', nativeName: 'ไทย' },
- { code: 'zh', name: 'Chinese', nativeName: '中文' },
- { code: 'zh-hans', name: 'Chinese', nativeName: '中文 (HANS)' },
- { code: 'zh-hant', name: 'Chinese', nativeName: '中文 (HANT)' },
- { code: 'zh-rhk', name: 'Chinese', nativeName: '中文 (RHK)' },
- { code: 'zh-rtw', name: 'Chinese', nativeName: '中文 (RTW)' },
+ { dayjsImport: loadDefaultDayJsLocale, code: 'en', name: 'English', nativeName: 'English' },
+ { dayjsImport: () => import('dayjs/locale/ca.js'), code: 'ca', name: 'Catalan; Valencian', nativeName: 'Català' },
+ { dayjsImport: () => import('dayjs/locale/de.js'), code: 'de', name: 'German', nativeName: 'Deutsch' },
+ { dayjsImport: () => import('dayjs/locale/es.js'), code: 'es', name: 'Spanish; Castilian', nativeName: 'Español' },
+ {
+ dayjsImport: () => import('dayjs/locale/es.js'),
+ code: 'es-419',
+ name: 'Spanish; Castilian',
+ nativeName: 'Español (Latinoamérica)',
+ },
+ { dayjsImport: () => import('dayjs/locale/fr.js'), code: 'fr', name: 'French', nativeName: 'Français' },
+ { dayjsImport: () => import('dayjs/locale/id.js'), code: 'id', name: 'Indonesian', nativeName: 'Indonesia' },
+ { dayjsImport: () => import('dayjs/locale/it.js'), code: 'it', name: 'Italian', nativeName: 'Italiano' },
+ { dayjsImport: () => import('dayjs/locale/pt.js'), code: 'pt', name: 'Portuguese', nativeName: 'Português' },
+ {
+ dayjsImport: () => import('dayjs/locale/pt.js'),
+ code: 'pt-pt',
+ name: 'Portuguese',
+ nativeName: 'Português (Portugal)',
+ },
+ {
+ dayjsImport: () => import('dayjs/locale/pt-br.js'),
+ code: 'pt-br',
+ name: 'Portuguese; Brasil',
+ nativeName: 'Português (Brasil)',
+ },
+ { dayjsImport: () => import('dayjs/locale/vi.js'), code: 'vi', name: 'Vietnamese', nativeName: 'Tiếng Việt' },
+ { dayjsImport: () => import('dayjs/locale/tr.js'), code: 'tr', name: 'Turkish', nativeName: 'Türkçe' },
+ { dayjsImport: () => import('dayjs/locale/ru.js'), code: 'ru', name: 'Russian', nativeName: 'русский' },
+ { dayjsImport: () => import('dayjs/locale/ar.js'), code: 'ar', name: 'Arabic', nativeName: 'العربية' },
+ { dayjsImport: () => import('dayjs/locale/hi.js'), code: 'hi', name: 'Hindi', nativeName: 'हिन्दी' },
+ { dayjsImport: () => import('dayjs/locale/th.js'), code: 'th', name: 'Thai', nativeName: 'ไทย' },
+ { dayjsImport: () => import('dayjs/locale/zh.js'), code: 'zh', name: 'Chinese', nativeName: '中文' },
+ { dayjsImport: () => import('dayjs/locale/zh-cn.js'), code: 'zh-hans', name: 'Chinese', nativeName: '中文 (HANS)' },
+ { dayjsImport: () => import('dayjs/locale/zh-hk.js'), code: 'zh-hant', name: 'Chinese', nativeName: '中文 (HANT)' },
+ { dayjsImport: () => import('dayjs/locale/zh-hk.js'), code: 'zh-rhk', name: 'Chinese', nativeName: '中文 (RHK)' },
+ { dayjsImport: () => import('dayjs/locale/zh-tw.js'), code: 'zh-rtw', name: 'Chinese', nativeName: '中文 (RTW)' },
- { code: 'ja', name: 'Japanese', nativeName: '日本語' },
- { code: 'ko', name: 'Korean', nativeName: '한국어' },
- { code: 'zu', name: 'Zulu', nativeName: 'isiZulu' },
- { code: 'xh', name: 'Xhosa', nativeName: 'isiXhosa' },
- { code: 'uk', name: 'Ukrainian', nativeName: 'Українська' },
- { code: 'ro', name: 'Romanian', nativeName: 'Română' },
- { code: 'bg', name: 'Bulgarian', nativeName: 'български' },
- { code: 'cs', name: 'Czech', nativeName: 'čeština' },
- { code: 'pl', name: 'Polish', nativeName: 'polski' },
- { code: 'no', name: 'Norwegian', nativeName: 'Norsk' },
- { code: 'nl', name: 'Dutch', nativeName: 'Nederlands' },
- { code: 'my', name: 'Burmese', nativeName: 'ဗမာစာ' },
- { code: 'ms', name: 'Malay', nativeName: 'Malaysia' },
- { code: 'mn', name: 'Mongolian', nativeName: 'Монгол' },
- { code: 'ml', name: 'Malayalam', nativeName: 'മലയാളം' },
- { code: 'ku', name: 'Kurdish', nativeName: 'Kurdî' },
- { code: 'hu', name: 'Hungarian', nativeName: 'Magyar' },
- { code: 'hr', name: 'Croatian', nativeName: 'Hrvatski' },
- { code: 'he', name: 'Hebrew', nativeName: 'עברית' },
- { code: 'fil', name: 'Filipino', nativeName: 'Filipino' },
- { code: 'fi', name: 'Finnish', nativeName: 'suomi' },
- { code: 'fa', name: 'Persian', nativeName: 'فارسی' },
- { code: 'eu', name: 'Basque', nativeName: 'euskara' },
- { code: 'el', name: 'Greek', nativeName: 'Ελληνικά' },
- { code: 'da', name: 'Danish', nativeName: 'dansk' },
- { code: 'bn', name: 'Bengali', nativeName: 'বাংলা' },
- { code: 'lt', name: 'Lithuanian', nativeName: 'lietuvių kalba' },
- { code: 'sh', name: 'Serbo-Croatian', nativeName: 'srpskohrvatski' },
+ { dayjsImport: () => import('dayjs/locale/ja.js'), code: 'ja', name: 'Japanese', nativeName: '日本語' },
+ { dayjsImport: () => import('dayjs/locale/ko.js'), code: 'ko', name: 'Korean', nativeName: '한국어' },
+ { dayjsImport: () => import('dayjs/locale/af.js'), code: 'zu', name: 'Zulu', nativeName: 'isiZulu' },
+ { dayjsImport: () => import('dayjs/locale/af.js'), code: 'xh', name: 'Xhosa', nativeName: 'isiXhosa' },
+ { dayjsImport: () => import('dayjs/locale/uk.js'), code: 'uk', name: 'Ukrainian', nativeName: 'Українська' },
+ { dayjsImport: () => import('dayjs/locale/ro.js'), code: 'ro', name: 'Romanian', nativeName: 'Română' },
+ { dayjsImport: () => import('dayjs/locale/bg.js'), code: 'bg', name: 'Bulgarian', nativeName: 'български' },
+ { dayjsImport: () => import('dayjs/locale/cs.js'), code: 'cs', name: 'Czech', nativeName: 'čeština' },
+ { dayjsImport: () => import('dayjs/locale/pl.js'), code: 'pl', name: 'Polish', nativeName: 'polski' },
+ { dayjsImport: () => import('dayjs/locale/nb.js'), code: 'no', name: 'Norwegian', nativeName: 'Norsk' },
+ { dayjsImport: () => import('dayjs/locale/nl.js'), code: 'nl', name: 'Dutch', nativeName: 'Nederlands' },
+ { dayjsImport: () => import('dayjs/locale/my.js'), code: 'my', name: 'Burmese', nativeName: 'ဗမာစာ' },
+ { dayjsImport: () => import('dayjs/locale/ms.js'), code: 'ms', name: 'Malay', nativeName: 'Malaysia' },
+ { dayjsImport: () => import('dayjs/locale/mn.js'), code: 'mn', name: 'Mongolian', nativeName: 'Монгол' },
+ { dayjsImport: () => import('dayjs/locale/ml.js'), code: 'ml', name: 'Malayalam', nativeName: 'മലയാളം' },
+ { dayjsImport: () => import('dayjs/locale/ku.js'), code: 'ku', name: 'Kurdish', nativeName: 'Kurdî' },
+ { dayjsImport: () => import('dayjs/locale/hu.js'), code: 'hu', name: 'Hungarian', nativeName: 'Magyar' },
+ { dayjsImport: () => import('dayjs/locale/hr.js'), code: 'hr', name: 'Croatian', nativeName: 'Hrvatski' },
+ { dayjsImport: () => import('dayjs/locale/he.js'), code: 'he', name: 'Hebrew', nativeName: 'עברית' },
+ { dayjsImport: () => import('dayjs/locale/tl-ph'), code: 'fil', name: 'Filipino', nativeName: 'Filipino' },
+ { dayjsImport: () => import('dayjs/locale/fi.js'), code: 'fi', name: 'Finnish', nativeName: 'suomi' },
+ { dayjsImport: () => import('dayjs/locale/fa.js'), code: 'fa', name: 'Persian', nativeName: 'فارسی' },
+ { dayjsImport: () => import('dayjs/locale/eu.js'), code: 'eu', name: 'Basque', nativeName: 'euskara' },
+ { dayjsImport: () => import('dayjs/locale/el.js'), code: 'el', name: 'Greek', nativeName: 'Ελληνικά' },
+ { dayjsImport: () => import('dayjs/locale/da.js'), code: 'da', name: 'Danish', nativeName: 'dansk' },
+ { dayjsImport: () => import('dayjs/locale/bn.js'), code: 'bn', name: 'Bengali', nativeName: 'বাংলা' },
+ { dayjsImport: () => import('dayjs/locale/lt.js'), code: 'lt', name: 'Lithuanian', nativeName: 'lietuvių kalba' },
+ {
+ dayjsImport: loadDefaultDayJsLocale,
+ code: 'sh',
+ name: 'Serbo-Croatian',
+ nativeName: 'srpskohrvatski',
+ },
- { code: 'af', name: 'Afrikaans', nativeName: 'Afrikaans' },
- { code: 'am', name: 'Amharic', nativeName: 'አማርኛ' },
- { code: 'az', name: 'Azerbaijani', nativeName: 'Azərbaycan' },
- { code: 'be', name: 'Belarusian', nativeName: 'беларуская' },
- { code: 'bs', name: 'Bosnian', nativeName: 'bosanski' },
- { code: 'sv', name: 'Swedish', nativeName: 'svenska' },
- { code: 'sv', name: 'Swedish', nativeName: 'svenska' },
+ { dayjsImport: () => import('dayjs/locale/af.js'), code: 'af', name: 'Afrikaans', nativeName: 'Afrikaans' },
+ { dayjsImport: () => import('dayjs/locale/am.js'), code: 'am', name: 'Amharic', nativeName: 'አማርኛ' },
+ { dayjsImport: () => import('dayjs/locale/az.js'), code: 'az', name: 'Azerbaijani', nativeName: 'Azərbaycan' },
+ { dayjsImport: () => import('dayjs/locale/be.js'), code: 'be', name: 'Belarusian', nativeName: 'беларуская' },
+ { dayjsImport: () => import('dayjs/locale/bs.js'), code: 'bs', name: 'Bosnian', nativeName: 'bosanski' },
+ { dayjsImport: () => import('dayjs/locale/sv.js'), code: 'sv', name: 'Swedish', nativeName: 'svenska' },
];
export function langCodeToName(code: string): string {
@@ -120,3 +141,20 @@ export const langSortCmp = (a: string, b: string) => {
return aLang > bLang ? 1 : -1;
};
+
+export const loadDayJsLocale = async (locale: string) => {
+ const lang = ISOLanguages.find(({ code }) => code.toLowerCase() === locale.toLowerCase());
+
+ try {
+ if (!lang) {
+ await loadDefaultDayJsLocale();
+ return false;
+ }
+
+ await lang.dayjsImport();
+ return true;
+ } catch (e) {
+ return false;
+ // ignore - dayjs falls back to en anyway
+ }
+};
diff --git a/yarn.lock b/yarn.lock
index f8c8001c..fbc057bf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1400,6 +1400,19 @@
clsx "^2.0.0"
prop-types "^15.8.1"
+"@mui/base@^5.0.0-beta.22":
+ version "5.0.0-beta.23"
+ resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.23.tgz#dd10dfc609d8937749521f940965f757fa3c0f2c"
+ integrity sha512-9L8SQUGAWtd/Qi7Qem26+oSSgpY7f2iQTuvcz/rsGpyZjSomMMO6lwYeQSA0CpWM7+aN7eGoSY/WV6wxJiIxXw==
+ dependencies:
+ "@babel/runtime" "^7.23.2"
+ "@floating-ui/react-dom" "^2.0.2"
+ "@mui/types" "^7.2.8"
+ "@mui/utils" "^5.14.17"
+ "@popperjs/core" "^2.11.8"
+ clsx "^2.0.0"
+ prop-types "^15.8.1"
+
"@mui/core-downloads-tracker@^5.14.16":
version "5.14.16"
resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.16.tgz#03ceb422d69a33e6c1cbd7e943cf60816878be2a"
@@ -1478,6 +1491,29 @@
prop-types "^15.8.1"
react-is "^18.2.0"
+"@mui/utils@^5.14.17":
+ version "5.14.17"
+ resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.17.tgz#8e2e7ca58865119eec8c6bdb359f539c25aaf576"
+ integrity sha512-yxnWgSS4J6DMFPw2Dof85yBkG02VTbEiqsikymMsnZnXDurtVGTIhlNuV24GTmFTuJMzEyTTU9UF+O7zaL8LEQ==
+ dependencies:
+ "@babel/runtime" "^7.23.2"
+ "@types/prop-types" "^15.7.9"
+ prop-types "^15.8.1"
+ react-is "^18.2.0"
+
+"@mui/x-date-pickers@^6.18.0":
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-6.18.0.tgz#3bc439d246315e957858f08a8c4a3a8fbe95adfd"
+ integrity sha512-y4UlkHQXiNRfb6FWQ/GWir0sZ+9kL+GEEZssG+XWP3KJ+d3lONRteusl4AJkYJBdIAOh+5LnMV9RAQKq9Sl7yw==
+ dependencies:
+ "@babel/runtime" "^7.23.2"
+ "@mui/base" "^5.0.0-beta.22"
+ "@mui/utils" "^5.14.16"
+ "@types/react-transition-group" "^4.4.8"
+ clsx "^2.0.0"
+ prop-types "^15.8.1"
+ react-transition-group "^4.4.5"
+
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -2634,6 +2670,11 @@ dataloader@^2.2.2:
resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.2.2.tgz#216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0"
integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==
+dayjs@^1.11.10:
+ version "1.11.10"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
+ integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
+
debounce@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"