U5 — the gate everything else has to pass
continuous_integration.yaml: six blocking checks, then a separate publish per environment so a Vite build never gets tagged for the wrong one, then a call into last commit's deploy workflow. Along the way: the lint list had drifted (two problems not in the requirement, one already fixed), and the Umami-origin gate needed a variable pair of its own since the backend's side of that comparison lives on the host, not in CI. Pinned the two vulnerable packages while at it.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { toast } from 'sonner';
|
||||
@@ -50,14 +50,14 @@ export function AddCmsInstanceDialog({ open, onOpenChange }: AddCmsInstanceDialo
|
||||
mode: 'onTouched',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
const handleOpenChange = (nextOpen: boolean) => {
|
||||
if (!nextOpen) {
|
||||
setServerError(null);
|
||||
addInstance.reset();
|
||||
reset();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open]);
|
||||
onOpenChange(nextOpen);
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(async (values) => {
|
||||
setServerError(null);
|
||||
@@ -71,7 +71,7 @@ export function AddCmsInstanceDialog({ open, onOpenChange }: AddCmsInstanceDialo
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('cms.add.title')}</DialogTitle>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { useState } from 'react';
|
||||
import { useForm, useWatch, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { toast } from 'sonner';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -60,7 +60,6 @@ export function SetStatusDialog({ instance, open, onOpenChange }: SetStatusDialo
|
||||
register,
|
||||
handleSubmit,
|
||||
control,
|
||||
watch,
|
||||
reset,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<SetStatusFormData>({
|
||||
@@ -69,21 +68,28 @@ export function SetStatusDialog({ instance, open, onOpenChange }: SetStatusDialo
|
||||
defaultValues: { status: 'Available', disableMessage: '' },
|
||||
});
|
||||
|
||||
const selectedStatus = watch('status');
|
||||
const selectedStatus = useWatch({ control, name: 'status' });
|
||||
|
||||
useEffect(() => {
|
||||
if (!open || !instance) {
|
||||
// Adjusts form values when the target instance changes, without an Effect
|
||||
// (https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes).
|
||||
const [syncedInstance, setSyncedInstance] = useState(instance);
|
||||
if (instance !== syncedInstance) {
|
||||
setSyncedInstance(instance);
|
||||
if (instance) {
|
||||
reset({ status: instance.status, disableMessage: instance.disableMessage ?? '' });
|
||||
} else {
|
||||
reset({ status: 'Available', disableMessage: '' });
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpenChange = (nextOpen: boolean) => {
|
||||
if (!nextOpen) {
|
||||
setServerError(null);
|
||||
updateStatus.reset();
|
||||
reset({ status: 'Available', disableMessage: '' });
|
||||
} else {
|
||||
reset({
|
||||
status: instance.status,
|
||||
disableMessage: instance.disableMessage ?? '',
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open, instance]);
|
||||
onOpenChange(nextOpen);
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(async (values) => {
|
||||
if (!instance) return;
|
||||
@@ -100,7 +106,7 @@ export function SetStatusDialog({ instance, open, onOpenChange }: SetStatusDialo
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('cms.setStatus.title')}</DialogTitle>
|
||||
|
||||
@@ -29,4 +29,5 @@ function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
export { Badge, badgeVariants };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { toast } from 'sonner';
|
||||
@@ -45,17 +45,6 @@ export function InviteUserDialog({ open, onOpenChange }: InviteUserDialogProps)
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
setStep(1);
|
||||
setInviteLink(null);
|
||||
setServerError(null);
|
||||
inviteUser.reset();
|
||||
reset();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open]);
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
@@ -66,6 +55,17 @@ export function InviteUserDialog({ open, onOpenChange }: InviteUserDialogProps)
|
||||
resolver: zodResolver(inviteUserSchema),
|
||||
});
|
||||
|
||||
const handleOpenChange = (nextOpen: boolean) => {
|
||||
if (!nextOpen) {
|
||||
setStep(1);
|
||||
setInviteLink(null);
|
||||
setServerError(null);
|
||||
inviteUser.reset();
|
||||
reset();
|
||||
}
|
||||
onOpenChange(nextOpen);
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(async (values) => {
|
||||
setServerError(null);
|
||||
try {
|
||||
@@ -84,7 +84,7 @@ export function InviteUserDialog({ open, onOpenChange }: InviteUserDialogProps)
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'sonner';
|
||||
import { Lock } from 'lucide-react';
|
||||
@@ -35,12 +35,16 @@ export function SettingsPage() {
|
||||
const [selectedMode, setSelectedMode] = useState<AvailabilityStatus>('Available');
|
||||
const [reason, setReason] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
// Adjusts local edit state when the fetched availability changes, without an Effect
|
||||
// (https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes).
|
||||
const [syncedAvailability, setSyncedAvailability] = useState(availability);
|
||||
if (availability !== syncedAvailability) {
|
||||
setSyncedAvailability(availability);
|
||||
if (availability) {
|
||||
setSelectedMode(availability.status);
|
||||
setReason(availability.message ?? '');
|
||||
}
|
||||
}, [availability]);
|
||||
}
|
||||
|
||||
const isMasterControlled = availability?.isMasterControlled ?? false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user