mirror of
https://github.com/umami-software/umami.git
synced 2026-02-05 13:17:19 +01:00
Merge branch 'dev' into jajaja
# Conflicts: # package.json # src/components/hooks/useTimezone.ts # yarn.lock
This commit is contained in:
commit
edb7022c55
13 changed files with 117 additions and 109 deletions
|
|
@ -11,7 +11,7 @@ import {
|
|||
import { useApi, useMessages, useModified } from '@/components/hooks';
|
||||
|
||||
export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) {
|
||||
const { formatMessage, labels, getMessage } = useMessages();
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { post, useMutation } = useApi();
|
||||
const { mutate, error } = useMutation({ mutationFn: (data: any) => post('/teams/join', data) });
|
||||
const ref = useRef(null);
|
||||
|
|
@ -28,7 +28,7 @@ export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose:
|
|||
};
|
||||
|
||||
return (
|
||||
<Form ref={ref} onSubmit={handleSubmit} error={error && getMessage(error)}>
|
||||
<Form ref={ref} onSubmit={handleSubmit} error={error}>
|
||||
<FormRow label={formatMessage(labels.accessCode)}>
|
||||
<FormInput name="accessCode" rules={{ required: formatMessage(labels.required) }}>
|
||||
<TextField autoComplete="off" />
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export function RealtimeLog({ data }: { data: RealtimeData }) {
|
|||
},
|
||||
];
|
||||
|
||||
const getTime = ({ createdAt, firstAt }) => formatTimezoneDate(firstAt || createdAt, 'h:mm:ss');
|
||||
const getTime = ({ createdAt, firstAt }) => formatTimezoneDate(firstAt || createdAt, 'pp');
|
||||
|
||||
const getColor = ({ id, sessionId }) => stringToColor(sessionId || id);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ export function SessionsWeekly({ websiteId }: { websiteId: string }) {
|
|||
const { data, ...props } = useWebsiteSessionsWeekly(websiteId);
|
||||
const { dateLocale } = useLocale();
|
||||
const { labels, formatMessage } = useMessages();
|
||||
const { weekStartsOn } = dateLocale.options;
|
||||
const daysOfWeek = Array(7)
|
||||
.fill(weekStartsOn)
|
||||
.map((d, i) => (d + i) % 7);
|
||||
|
||||
const [, max] = data
|
||||
? data.reduce((arr: number[], hours: number[], index: number) => {
|
||||
|
|
@ -40,7 +44,9 @@ export function SessionsWeekly({ websiteId }: { websiteId: string }) {
|
|||
{Array(24)
|
||||
.fill(null)
|
||||
.map((_, i) => {
|
||||
const label = format(addHours(startOfDay(new Date()), i), 'haaa');
|
||||
const label = format(addHours(startOfDay(new Date()), i), 'p', { locale: dateLocale })
|
||||
.replace(/\D00 ?/, '')
|
||||
.toLowerCase();
|
||||
return (
|
||||
<div key={i} className={styles.hour}>
|
||||
{label}
|
||||
|
|
@ -48,33 +54,35 @@ export function SessionsWeekly({ websiteId }: { websiteId: string }) {
|
|||
);
|
||||
})}
|
||||
</div>
|
||||
{data?.map((day: number[], index: number) => {
|
||||
return (
|
||||
<div key={index} className={styles.day}>
|
||||
<div className={styles.header}>
|
||||
{format(getDayOfWeekAsDate(index), 'EEE', { locale: dateLocale })}
|
||||
{data &&
|
||||
daysOfWeek.map((index: number) => {
|
||||
const day = data[index];
|
||||
return (
|
||||
<div key={index} className={styles.day}>
|
||||
<div className={styles.header}>
|
||||
{format(getDayOfWeekAsDate(index), 'EEE', { locale: dateLocale })}
|
||||
</div>
|
||||
{day?.map((hour: number) => {
|
||||
const pct = hour / max;
|
||||
return (
|
||||
<div key={hour} className={classNames(styles.cell)}>
|
||||
{hour > 0 && (
|
||||
<TooltipPopup
|
||||
label={`${formatMessage(labels.visitors)}: ${hour}`}
|
||||
position="right"
|
||||
>
|
||||
<div
|
||||
className={styles.block}
|
||||
style={{ opacity: pct, transform: `scale(${pct})` }}
|
||||
/>
|
||||
</TooltipPopup>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{day?.map((hour: number, n) => {
|
||||
const pct = hour / max;
|
||||
return (
|
||||
<div key={n} className={classNames(styles.cell)}>
|
||||
{hour > 0 && (
|
||||
<TooltipPopup
|
||||
label={`${formatMessage(labels.visitors)}: ${hour}`}
|
||||
position="right"
|
||||
>
|
||||
<div
|
||||
className={styles.block}
|
||||
style={{ opacity: pct, transform: `scale(${pct})` }}
|
||||
/>
|
||||
</TooltipPopup>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</LoadingPanel>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export function SessionActivity({
|
|||
return (
|
||||
<Fragment key={eventId}>
|
||||
{showHeader && (
|
||||
<div className={styles.header}>{formatTimezoneDate(createdAt, 'EEEE, PPP')}</div>
|
||||
<div className={styles.header}>{formatTimezoneDate(createdAt, 'PPPP')}</div>
|
||||
)}
|
||||
<div key={eventId} className={styles.row}>
|
||||
<div className={styles.time}>
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ export function SessionInfo({ data }) {
|
|||
</dd>
|
||||
|
||||
<dt>{formatMessage(labels.lastSeen)}</dt>
|
||||
<dd>{formatTimezoneDate(data?.lastAt, 'EEEE, PPPpp')}</dd>
|
||||
<dd>{formatTimezoneDate(data?.lastAt, 'PPPPpp')}</dd>
|
||||
|
||||
<dt>{formatMessage(labels.firstSeen)}</dt>
|
||||
<dd>{formatTimezoneDate(data?.firstAt, 'EEEE, PPPpp')}</dd>
|
||||
<dd>{formatTimezoneDate(data?.firstAt, 'PPPPpp')}</dd>
|
||||
|
||||
<dt>{formatMessage(labels.country)}</dt>
|
||||
<dd>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { reportParms } from '@/lib/schema';
|
|||
export async function POST(request: Request) {
|
||||
const schema = z.object({
|
||||
...reportParms,
|
||||
steps: z.number().min(3).max(7),
|
||||
steps: z.coerce.number().min(3).max(7),
|
||||
startStep: z.string(),
|
||||
endStep: z.string(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from 'zod';
|
||||
import { unauthorized, json, badRequest } from '@/lib/response';
|
||||
import { canAddUserToTeam, canUpdateTeam } from '@/lib/auth';
|
||||
import { canAddUserToTeam, canViewTeam } from '@/lib/auth';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { pagingParams, roleParam } from '@/lib/schema';
|
||||
import { createTeamUser, getTeamUser, getTeamUsers } from '@/queries';
|
||||
|
|
@ -18,7 +18,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ team
|
|||
|
||||
const { teamId } = await params;
|
||||
|
||||
if (!(await canUpdateTeam(auth, teamId))) {
|
||||
if (!(await canViewTeam(auth, teamId))) {
|
||||
return unauthorized('You must be the owner of this team.');
|
||||
}
|
||||
|
||||
|
|
@ -45,12 +45,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ team
|
|||
return json(users);
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ teamId: string; userId: string }> },
|
||||
) {
|
||||
export async function POST(request: Request, { params }: { params: Promise<{ teamId: string }> }) {
|
||||
const schema = z.object({
|
||||
userId: z.string(),
|
||||
userId: z.string().uuid(),
|
||||
role: roleParam,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import Logo from '@/assets/logo.svg';
|
|||
import styles from './LoginForm.module.css';
|
||||
|
||||
export function LoginForm() {
|
||||
const { formatMessage, labels, getMessage } = useMessages();
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const router = useRouter();
|
||||
const { post, useMutation } = useApi();
|
||||
const { mutate, error, isPending } = useMutation({
|
||||
|
|
@ -40,7 +40,7 @@ export function LoginForm() {
|
|||
<Logo />
|
||||
</Icon>
|
||||
<div className={styles.title}>umami</div>
|
||||
<Form className={styles.form} onSubmit={handleSubmit} error={getMessage(error)}>
|
||||
<Form className={styles.form} onSubmit={handleSubmit} error={error}>
|
||||
<FormRow label={formatMessage(labels.username)}>
|
||||
<FormInput
|
||||
data-test="input-username"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue