From 851a3346a903719790b1526af4f5b48de883b003 Mon Sep 17 00:00:00 2001 From: Chaim Lev-Ari Date: Tue, 24 Jan 2023 12:20:55 +0530 Subject: [PATCH] fix(edge/update): remove schedule date for old envs [EE-3023] (#8315) --- app/assets/css/icon.css | 5 --- app/react/components/InformationPanel.tsx | 10 ++--- app/react/components/Tip/TextTip/TextTip.tsx | 38 ++++++++----------- .../CreateView/CreateView.tsx | 4 +- .../common/ScheduledTimeField.tsx | 8 ++++ .../common/UpdateScheduleDetailsFieldset.tsx | 13 ++++++- .../update-schedules/common/validation.ts | 29 ++++++++------ 7 files changed, 57 insertions(+), 50 deletions(-) diff --git a/app/assets/css/icon.css b/app/assets/css/icon.css index bed16a121..e7818b101 100644 --- a/app/assets/css/icon.css +++ b/app/assets/css/icon.css @@ -121,11 +121,6 @@ pr-icon { width: 20px; } -.icon-container { - display: flex; - align-items: center; -} - .btn-only-icon { padding: 6px; } diff --git a/app/react/components/InformationPanel.tsx b/app/react/components/InformationPanel.tsx index ba58eb8dd..b440585d7 100644 --- a/app/react/components/InformationPanel.tsx +++ b/app/react/components/InformationPanel.tsx @@ -25,14 +25,10 @@ export function InformationPanel({
{title && ( -
- {title} +
+ {title} {!!onDismiss && ( - + diff --git a/app/react/components/Tip/TextTip/TextTip.tsx b/app/react/components/Tip/TextTip/TextTip.tsx index df4569df8..54d11898a 100644 --- a/app/react/components/Tip/TextTip/TextTip.tsx +++ b/app/react/components/Tip/TextTip/TextTip.tsx @@ -1,41 +1,35 @@ -import clsx from 'clsx'; import { PropsWithChildren } from 'react'; import { AlertCircle } from 'lucide-react'; -import { Icon } from '@@/Icon'; +import { Icon, IconMode } from '@@/Icon'; type Color = 'orange' | 'blue'; export interface Props { + icon?: React.ReactNode; color?: Color; } export function TextTip({ color = 'orange', + icon = AlertCircle, children, }: PropsWithChildren) { - let iconClass: string; - - switch (color) { - case 'blue': - iconClass = 'icon-primary'; - break; - case 'orange': - iconClass = 'icon-warning'; - break; - default: - iconClass = 'icon-warning'; - } - return ( -

- - - +

+ + {children}

); } + +function getMode(color: Color): IconMode { + switch (color) { + case 'blue': + return 'primary'; + case 'orange': + default: + return 'warning'; + } +} diff --git a/app/react/portainer/environments/update-schedules/CreateView/CreateView.tsx b/app/react/portainer/environments/update-schedules/CreateView/CreateView.tsx index 8363c1104..538fa55b2 100644 --- a/app/react/portainer/environments/update-schedules/CreateView/CreateView.tsx +++ b/app/react/portainer/environments/update-schedules/CreateView/CreateView.tsx @@ -4,7 +4,6 @@ import { useRouter } from '@uirouter/react'; import { notifySuccess } from '@/portainer/services/notifications'; import { withLimitToBE } from '@/react/hooks/useLimitToBE'; -import { isoDate } from '@/portainer/filters/filters'; import { PageHeader } from '@@/PageHeader'; import { Widget } from '@@/Widget'; @@ -21,6 +20,7 @@ import { useList } from '../queries/list'; import { NameField } from '../common/NameField'; import { EdgeGroupsField } from '../common/EdgeGroupsField'; import { BetaAlert } from '../common/BetaAlert'; +import { defaultValue } from '../common/ScheduledTimeField'; export default withLimitToBE(CreateView); @@ -30,7 +30,7 @@ function CreateView() { groupIds: [], type: ScheduleType.Update, version: '', - scheduledTime: isoDate(Date.now() + 24 * 60 * 60 * 1000), + scheduledTime: defaultValue(), }; const schedulesQuery = useList(); diff --git a/app/react/portainer/environments/update-schedules/common/ScheduledTimeField.tsx b/app/react/portainer/environments/update-schedules/common/ScheduledTimeField.tsx index 0ee11f2d5..a36bde330 100644 --- a/app/react/portainer/environments/update-schedules/common/ScheduledTimeField.tsx +++ b/app/react/portainer/environments/update-schedules/common/ScheduledTimeField.tsx @@ -25,6 +25,10 @@ export function ScheduledTimeField({ disabled }: Props) { const dateValue = useMemo(() => parseIsoDate(value), [value]); + if (!value) { + return null; + } + return ( {!disabled ? ( @@ -64,6 +68,10 @@ export function timeValidation() { ); } +export function defaultValue() { + return isoDate(Date.now() + 24 * 60 * 60 * 1000); +} + function isValidDate(date: Date) { return date instanceof Date && !Number.isNaN(date.valueOf()); } diff --git a/app/react/portainer/environments/update-schedules/common/UpdateScheduleDetailsFieldset.tsx b/app/react/portainer/environments/update-schedules/common/UpdateScheduleDetailsFieldset.tsx index f76cc8062..72f05a71a 100644 --- a/app/react/portainer/environments/update-schedules/common/UpdateScheduleDetailsFieldset.tsx +++ b/app/react/portainer/environments/update-schedules/common/UpdateScheduleDetailsFieldset.tsx @@ -1,6 +1,7 @@ import { useFormikContext } from 'formik'; import semverCompare from 'semver-compare'; import _ from 'lodash'; +import { useEffect } from 'react'; import { EdgeTypes, EnvironmentId } from '@/react/portainer/environments/types'; import { useEnvironmentList } from '@/react/portainer/environments/queries/useEnvironmentList'; @@ -10,10 +11,10 @@ import { TextTip } from '@@/Tip/TextTip'; import { FormValues } from './types'; import { useEdgeGroupsEnvironmentIds } from './useEdgeGroupsEnvironmentIds'; import { VersionSelect } from './VersionSelect'; -import { ScheduledTimeField } from './ScheduledTimeField'; +import { defaultValue, ScheduledTimeField } from './ScheduledTimeField'; export function UpdateScheduleDetailsFieldset() { - const { values } = useFormikContext(); + const { values, setFieldValue } = useFormikContext(); const environmentIdsQuery = useEdgeGroupsEnvironmentIds(values.groupIds); @@ -29,6 +30,14 @@ export function UpdateScheduleDetailsFieldset() { const hasNoTimeZone = environments.some((env) => !env.LocalTimeZone); const hasTimeZone = environments.some((env) => env.LocalTimeZone); + useEffect(() => { + if (!hasTimeZone) { + setFieldValue('scheduledTime', ''); + } else if (!values.scheduledTime) { + setFieldValue('scheduledTime', defaultValue()); + } + }, [setFieldValue, hasTimeZone, values.scheduledTime]); + return ( <> {edgeGroupsEnvironmentIds.length > 0 ? ( diff --git a/app/react/portainer/environments/update-schedules/common/validation.ts b/app/react/portainer/environments/update-schedules/common/validation.ts index 10b2f18f3..ed8bcf93c 100644 --- a/app/react/portainer/environments/update-schedules/common/validation.ts +++ b/app/react/portainer/environments/update-schedules/common/validation.ts @@ -1,27 +1,32 @@ -import { array, object, string } from 'yup'; +import { array, object, SchemaOf, string } from 'yup'; + +import { parseIsoDate } from '@/portainer/filters/filters'; import { EdgeUpdateSchedule, ScheduleType } from '../types'; import { nameValidation } from './NameField'; import { typeValidation } from './ScheduleTypeSelector'; +import { FormValues } from './types'; export function validation( schedules: EdgeUpdateSchedule[], currentId?: EdgeUpdateSchedule['id'] -) { +): SchemaOf { return object({ groupIds: array().min(1, 'At least one group is required'), name: nameValidation(schedules, currentId), type: typeValidation(), - // time: number() - // .min(Date.now() / 1000) - // .required(), - version: string().when('type', { - is: ScheduleType.Update, - // update type - then: (schema) => schema.required('Version is required'), - // rollback - otherwise: (schema) => schema.required('No rollback options available'), - }), + scheduledTime: string() + .default('') + .test('valid', (value) => !value || parseIsoDate(value) !== null), + version: string() + .default('') + .when('type', { + is: ScheduleType.Update, + // update type + then: (schema) => schema.required('Version is required'), + // rollback + otherwise: (schema) => schema.required('No rollback options available'), + }), }); }