Merge branch 'dev' into jajaja

This commit is contained in:
Mike Cao 2025-03-08 07:25:40 -08:00
commit b331da193f
27 changed files with 217 additions and 50 deletions

View file

@ -41,7 +41,7 @@ export function ReportDeleteButton({
{({ close }) => (
<ConfirmationForm
message={formatMessage(messages.confirmDelete, {
target: <b key="report-name">{reportName}</b>,
target: <b key={messages.confirmDelete.id}>{reportName}</b>,
})}
isLoading={isPending}
error={error}

View file

@ -34,7 +34,9 @@ export function TeamLeaveForm({
return (
<ConfirmationForm
buttonLabel={formatMessage(labels.leave)}
message={formatMessage(messages.confirmLeave, { target: <b>{teamName}</b> })}
message={formatMessage(messages.confirmLeave, {
target: <b key={messages.confirmLeave.id}>{teamName}</b>,
})}
onConfirm={handleConfirm}
onClose={onClose}
isLoading={isPending}

View file

@ -24,7 +24,7 @@ export function UserAddButton({ onSave }: { onSave?: () => void }) {
return (
<DialogTrigger>
<Button variant="primary">
<Button variant="primary" data-test="button-create-user">
<Icon>
<Icons.Plus />
</Icon>

View file

@ -11,6 +11,7 @@ import {
} from '@umami/react-zen';
import { useApi, useMessages } from '@/components/hooks';
import { ROLES } from '@/lib/constants';
import { messages } from '@/components/messages';
export function UserAddForm({ onSave, onClose }) {
const { post, useMutation } = useApi();
@ -35,14 +36,14 @@ export function UserAddForm({ onSave, onClose }) {
name="username"
rules={{ required: formatMessage(labels.required) }}
>
<TextField autoComplete="new-username" />
<TextField autoComplete="new-username" data-test="input-username" />
</FormField>
<FormField
label={formatMessage(labels.password)}
name="password"
rules={{ required: formatMessage(labels.required) }}
>
<PasswordField autoComplete="new-password" />
<PasswordField autoComplete="new-password" data-test="input-password" />
</FormField>
<FormField
label={formatMessage(labels.role)}
@ -50,13 +51,13 @@ export function UserAddForm({ onSave, onClose }) {
rules={{ required: formatMessage(labels.required) }}
>
<Select>
<ListItem id={ROLES.viewOnly}>{formatMessage(labels.viewOnly)}</ListItem>
<ListItem id={ROLES.user}>{formatMessage(labels.user)}</ListItem>
<ListItem id={ROLES.admin}>{formatMessage(labels.admin)}</ListItem>
<ListItem id={ROLES.viewOnly} data-test="dropdown-item-viewOnly">{formatMessage(labels.viewOnly)}</ListItem>
<ListItem id={ROLES.user} data-test="dropdown-item-user">{formatMessage(labels.user)}</ListItem>
<ListItem id={ROLES.admin} data-test="dropdown-item-admin">{formatMessage(labels.admin)}</ListItem>
</Select>
</FormField>
<FormButtons>
<FormSubmitButton variant="primary" disabled={false}>
<FormSubmitButton variant="primary" data-test="button-submit" isDisabled={false}>
{formatMessage(labels.save)}
</FormSubmitButton>
<Button isDisabled={isPending} onPress={onClose}>

View file

@ -16,7 +16,7 @@ export function UserDeleteButton({
return (
<DialogTrigger>
<Button isDisabled={userId === user?.id}>
<Button isDisabled={userId === user?.id} data-test="button-delete">
<Icon size="sm">
<Icons.Trash />
</Icon>

View file

@ -22,7 +22,9 @@ export function UserDeleteForm({ userId, username, onSave, onClose }) {
return (
<ConfirmationForm
message={formatMessage(messages.confirmDelete, { target: <b>{username}</b> })}
message={formatMessage(messages.confirmDelete, {
target: <b key={messages.confirmDelete.id}>{username}</b>,
})}
onConfirm={handleConfirm}
onClose={onClose}
buttonLabel={formatMessage(labels.delete)}

View file

@ -3,7 +3,8 @@ import Link from 'next/link';
import { formatDistance } from 'date-fns';
import { ROLES } from '@/lib/constants';
import { useMessages, useLocale } from '@/components/hooks';
import { UserDeleteButton } from './UserDeleteButton';
import UserDeleteButton from './UserDeleteButton';
import LinkButton from '@/components/common/LinkButton';
export function UsersTable({
data = [],
@ -44,7 +45,7 @@ export function UsersTable({
<Row gap="3">
<UserDeleteButton userId={id} username={username} />
<Button asChild>
<Link href={`/settings/users/${id}`}>
<Link href={`/settings/users/${id}`} data-test="link-button-edit">
<Icon>
<Icons.Edit />
</Icon>

View file

@ -47,7 +47,7 @@ export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () =
return (
<Form onSubmit={handleSubmit} error={getMessage(error)} values={user} style={{ width: 300 }}>
<FormField name="username" label={formatMessage(labels.username)}>
<TextField />
<TextField data-test="input-username" />
</FormField>
<FormField
name="password"
@ -56,7 +56,7 @@ export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () =
minLength: { value: 8, message: formatMessage(messages.minPasswordLength, { n: 8 }) },
}}
>
<PasswordField autoComplete="new-password" />
<PasswordField autoComplete="new-password" data-test="input-password" />
</FormField>
{user.id !== login.id && (
@ -66,14 +66,14 @@ export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () =
rules={{ required: formatMessage(labels.required) }}
>
<Select defaultSelectedKey={user.role}>
<ListItem id={ROLES.viewOnly}>{formatMessage(labels.viewOnly)}</ListItem>
<ListItem id={ROLES.user}>{formatMessage(labels.user)}</ListItem>
<ListItem id={ROLES.admin}>{formatMessage(labels.admin)}</ListItem>
<ListItem id={ROLES.viewOnly} data-test="dropdown-item-viewOnly">{formatMessage(labels.viewOnly)}</ListItem>
<ListItem id={ROLES.user} data-test="dropdown-item-user">{formatMessage(labels.user)}</ListItem>
<ListItem id={ROLES.admin} data-test="dropdown-item-admin">{formatMessage(labels.admin)}</ListItem>
</Select>
</FormField>
)}
<FormButtons>
<FormSubmitButton variant="primary">{formatMessage(labels.save)}</FormSubmitButton>
<FormSubmitButton data-test="button-submit" variant="primary">{formatMessage(labels.save)}</FormSubmitButton>
</FormButtons>
</Form>
);

View file

@ -45,7 +45,7 @@ export function TeamMemberRemoveButton({
{({ close }) => (
<ConfirmationForm
message={formatMessage(messages.confirmRemove, {
target: <b key="username">{userName}</b>,
target: <b key={messages.confirmRemove.id}>{userName}</b>,
})}
isLoading={isPending}
error={error}

View file

@ -9,8 +9,8 @@ export async function POST(request: Request) {
const schema = z.object({
...reportParms,
steps: z.coerce.number().min(3).max(7),
startStep: z.string(),
endStep: z.string(),
startStep: z.string().optional(),
endStep: z.string().optional(),
});
const { auth, body, error } = await parseRequest(request, schema);

View file

@ -10,6 +10,7 @@ import { createToken, parseToken } from '@/lib/jwt';
import { secret, uuid, hash } from '@/lib/crypto';
import { COLLECTION_TYPE } from '@/lib/constants';
import { anyObjectParam, urlOrPathParam } from '@/lib/schema';
import { safeDecodeURI, safeDecodeURIComponent } from '@/lib/url';
import { createSession, saveEvent, saveSessionData } from '@/queries';
const schema = z.object({
@ -168,12 +169,12 @@ export async function POST(request: Request) {
websiteId,
sessionId,
visitId,
urlPath,
urlPath: safeDecodeURI(urlPath),
urlQuery,
referrerPath,
referrerPath: safeDecodeURI(referrerPath),
referrerQuery,
referrerDomain,
pageTitle: title,
pageTitle: safeDecodeURIComponent(title),
eventName: name,
eventData: data,
hostname: hostname || urlDomain,