fix(edge/update): remove schedule date for old envs [EE-3023] (#8315)

pull/8283/head
Chaim Lev-Ari 2023-01-24 12:20:55 +05:30 committed by GitHub
parent c9aae27b29
commit 851a3346a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 57 additions and 50 deletions

View File

@ -121,11 +121,6 @@ pr-icon {
width: 20px; width: 20px;
} }
.icon-container {
display: flex;
align-items: center;
}
.btn-only-icon { .btn-only-icon {
padding: 6px; padding: 6px;
} }

View File

@ -25,14 +25,10 @@ export function InformationPanel({
<WidgetBody className={bodyClassName}> <WidgetBody className={bodyClassName}>
<div style={wrapperStyle}> <div style={wrapperStyle}>
{title && ( {title && (
<div className="col-sm-12 form-section-title"> <div className="form-section-title">
<span style={{ float: 'left' }}>{title}</span> <span>{title}</span>
{!!onDismiss && ( {!!onDismiss && (
<span <span className="small" style={{ float: 'right' }}>
className="small"
style={{ float: 'right' }}
ng-if="dismissAction"
>
<Button color="link" icon={X} onClick={() => onDismiss()}> <Button color="link" icon={X} onClick={() => onDismiss()}>
dismiss dismiss
</Button> </Button>

View File

@ -1,41 +1,35 @@
import clsx from 'clsx';
import { PropsWithChildren } from 'react'; import { PropsWithChildren } from 'react';
import { AlertCircle } from 'lucide-react'; import { AlertCircle } from 'lucide-react';
import { Icon } from '@@/Icon'; import { Icon, IconMode } from '@@/Icon';
type Color = 'orange' | 'blue'; type Color = 'orange' | 'blue';
export interface Props { export interface Props {
icon?: React.ReactNode;
color?: Color; color?: Color;
} }
export function TextTip({ export function TextTip({
color = 'orange', color = 'orange',
icon = AlertCircle,
children, children,
}: PropsWithChildren<Props>) { }: PropsWithChildren<Props>) {
let iconClass: string;
switch (color) {
case 'blue':
iconClass = 'icon-primary';
break;
case 'orange':
iconClass = 'icon-warning';
break;
default:
iconClass = 'icon-warning';
}
return ( return (
<p className="small vertical-center"> <p className="small flex items-center gap-1">
<i className="icon-container"> <Icon icon={icon} mode={getMode(color)} />
<Icon
icon={AlertCircle}
className={clsx(`${iconClass}`, 'space-right')}
/>
</i>
<span className="text-muted">{children}</span> <span className="text-muted">{children}</span>
</p> </p>
); );
} }
function getMode(color: Color): IconMode {
switch (color) {
case 'blue':
return 'primary';
case 'orange':
default:
return 'warning';
}
}

View File

@ -4,7 +4,6 @@ import { useRouter } from '@uirouter/react';
import { notifySuccess } from '@/portainer/services/notifications'; import { notifySuccess } from '@/portainer/services/notifications';
import { withLimitToBE } from '@/react/hooks/useLimitToBE'; import { withLimitToBE } from '@/react/hooks/useLimitToBE';
import { isoDate } from '@/portainer/filters/filters';
import { PageHeader } from '@@/PageHeader'; import { PageHeader } from '@@/PageHeader';
import { Widget } from '@@/Widget'; import { Widget } from '@@/Widget';
@ -21,6 +20,7 @@ import { useList } from '../queries/list';
import { NameField } from '../common/NameField'; import { NameField } from '../common/NameField';
import { EdgeGroupsField } from '../common/EdgeGroupsField'; import { EdgeGroupsField } from '../common/EdgeGroupsField';
import { BetaAlert } from '../common/BetaAlert'; import { BetaAlert } from '../common/BetaAlert';
import { defaultValue } from '../common/ScheduledTimeField';
export default withLimitToBE(CreateView); export default withLimitToBE(CreateView);
@ -30,7 +30,7 @@ function CreateView() {
groupIds: [], groupIds: [],
type: ScheduleType.Update, type: ScheduleType.Update,
version: '', version: '',
scheduledTime: isoDate(Date.now() + 24 * 60 * 60 * 1000), scheduledTime: defaultValue(),
}; };
const schedulesQuery = useList(); const schedulesQuery = useList();

View File

@ -25,6 +25,10 @@ export function ScheduledTimeField({ disabled }: Props) {
const dateValue = useMemo(() => parseIsoDate(value), [value]); const dateValue = useMemo(() => parseIsoDate(value), [value]);
if (!value) {
return null;
}
return ( return (
<FormControl label="Schedule date & time" errors={error}> <FormControl label="Schedule date & time" errors={error}>
{!disabled ? ( {!disabled ? (
@ -64,6 +68,10 @@ export function timeValidation() {
); );
} }
export function defaultValue() {
return isoDate(Date.now() + 24 * 60 * 60 * 1000);
}
function isValidDate(date: Date) { function isValidDate(date: Date) {
return date instanceof Date && !Number.isNaN(date.valueOf()); return date instanceof Date && !Number.isNaN(date.valueOf());
} }

View File

@ -1,6 +1,7 @@
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import semverCompare from 'semver-compare'; import semverCompare from 'semver-compare';
import _ from 'lodash'; import _ from 'lodash';
import { useEffect } from 'react';
import { EdgeTypes, EnvironmentId } from '@/react/portainer/environments/types'; import { EdgeTypes, EnvironmentId } from '@/react/portainer/environments/types';
import { useEnvironmentList } from '@/react/portainer/environments/queries/useEnvironmentList'; import { useEnvironmentList } from '@/react/portainer/environments/queries/useEnvironmentList';
@ -10,10 +11,10 @@ import { TextTip } from '@@/Tip/TextTip';
import { FormValues } from './types'; import { FormValues } from './types';
import { useEdgeGroupsEnvironmentIds } from './useEdgeGroupsEnvironmentIds'; import { useEdgeGroupsEnvironmentIds } from './useEdgeGroupsEnvironmentIds';
import { VersionSelect } from './VersionSelect'; import { VersionSelect } from './VersionSelect';
import { ScheduledTimeField } from './ScheduledTimeField'; import { defaultValue, ScheduledTimeField } from './ScheduledTimeField';
export function UpdateScheduleDetailsFieldset() { export function UpdateScheduleDetailsFieldset() {
const { values } = useFormikContext<FormValues>(); const { values, setFieldValue } = useFormikContext<FormValues>();
const environmentIdsQuery = useEdgeGroupsEnvironmentIds(values.groupIds); const environmentIdsQuery = useEdgeGroupsEnvironmentIds(values.groupIds);
@ -29,6 +30,14 @@ export function UpdateScheduleDetailsFieldset() {
const hasNoTimeZone = environments.some((env) => !env.LocalTimeZone); const hasNoTimeZone = environments.some((env) => !env.LocalTimeZone);
const hasTimeZone = 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 ( return (
<> <>
{edgeGroupsEnvironmentIds.length > 0 ? ( {edgeGroupsEnvironmentIds.length > 0 ? (

View File

@ -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 { EdgeUpdateSchedule, ScheduleType } from '../types';
import { nameValidation } from './NameField'; import { nameValidation } from './NameField';
import { typeValidation } from './ScheduleTypeSelector'; import { typeValidation } from './ScheduleTypeSelector';
import { FormValues } from './types';
export function validation( export function validation(
schedules: EdgeUpdateSchedule[], schedules: EdgeUpdateSchedule[],
currentId?: EdgeUpdateSchedule['id'] currentId?: EdgeUpdateSchedule['id']
) { ): SchemaOf<FormValues> {
return object({ return object({
groupIds: array().min(1, 'At least one group is required'), groupIds: array().min(1, 'At least one group is required'),
name: nameValidation(schedules, currentId), name: nameValidation(schedules, currentId),
type: typeValidation(), type: typeValidation(),
// time: number() scheduledTime: string()
// .min(Date.now() / 1000) .default('')
// .required(), .test('valid', (value) => !value || parseIsoDate(value) !== null),
version: string().when('type', { version: string()
is: ScheduleType.Update, .default('')
// update type .when('type', {
then: (schema) => schema.required('Version is required'), is: ScheduleType.Update,
// rollback // update type
otherwise: (schema) => schema.required('No rollback options available'), then: (schema) => schema.required('Version is required'),
}), // rollback
otherwise: (schema) => schema.required('No rollback options available'),
}),
}); });
} }