diff --git a/packages/graphql/src/resolvers/auth/login.ts b/packages/graphql/src/resolvers/auth/login.ts index 241c204eb..fe588a563 100644 --- a/packages/graphql/src/resolvers/auth/login.ts +++ b/packages/graphql/src/resolvers/auth/login.ts @@ -19,8 +19,8 @@ export function login(collection: Collection): any { const result = await loginOperation(options) const cookie = generatePayloadCookie({ - collectionConfig: collection.config, - payload: context.req.payload, + collectionAuthConfig: collection.config.auth, + cookiePrefix: context.req.payload.config.cookiePrefix, token: result.token, }) diff --git a/packages/graphql/src/resolvers/auth/logout.ts b/packages/graphql/src/resolvers/auth/logout.ts index c81dbb799..7277ea5a2 100644 --- a/packages/graphql/src/resolvers/auth/logout.ts +++ b/packages/graphql/src/resolvers/auth/logout.ts @@ -13,8 +13,9 @@ export function logout(collection: Collection): any { const result = await logoutOperation(options) const expiredCookie = generateExpiredPayloadCookie({ - collectionConfig: collection.config, - payload: context.req.payload, + collectionAuthConfig: collection.config.auth, + config: context.req.payload.config, + cookiePrefix: context.req.payload.config.cookiePrefix, }) context.headers['Set-Cookie'] = expiredCookie return result diff --git a/packages/graphql/src/resolvers/auth/refresh.ts b/packages/graphql/src/resolvers/auth/refresh.ts index ef25253e5..0f5dc8912 100644 --- a/packages/graphql/src/resolvers/auth/refresh.ts +++ b/packages/graphql/src/resolvers/auth/refresh.ts @@ -14,8 +14,8 @@ export function refresh(collection: Collection): any { const result = await refreshOperation(options) const cookie = generatePayloadCookie({ - collectionConfig: collection.config, - payload: context.req.payload, + collectionAuthConfig: collection.config.auth, + cookiePrefix: context.req.payload.config.cookiePrefix, token: result.refreshedToken, }) context.headers['Set-Cookie'] = cookie diff --git a/packages/graphql/src/resolvers/auth/resetPassword.ts b/packages/graphql/src/resolvers/auth/resetPassword.ts index b17f4afa1..161e69322 100644 --- a/packages/graphql/src/resolvers/auth/resetPassword.ts +++ b/packages/graphql/src/resolvers/auth/resetPassword.ts @@ -23,8 +23,8 @@ export function resetPassword(collection: Collection): any { const result = await resetPasswordOperation(options) const cookie = generatePayloadCookie({ - collectionConfig: collection.config, - payload: context.req.payload, + collectionAuthConfig: collection.config.auth, + cookiePrefix: context.req.payload.config.cookiePrefix, token: result.token, }) context.headers['Set-Cookie'] = cookie diff --git a/packages/next/src/elements/FormHeader/index.scss b/packages/next/src/elements/FormHeader/index.scss new file mode 100644 index 000000000..950597471 --- /dev/null +++ b/packages/next/src/elements/FormHeader/index.scss @@ -0,0 +1,6 @@ +.form-header { + display: flex; + flex-direction: column; + gap: calc(var(--base) * .5); + margin-bottom: var(--base); +} diff --git a/packages/next/src/elements/FormHeader/index.tsx b/packages/next/src/elements/FormHeader/index.tsx new file mode 100644 index 000000000..22a07eb8f --- /dev/null +++ b/packages/next/src/elements/FormHeader/index.tsx @@ -0,0 +1,22 @@ +import React from 'react' + +import './index.scss' + +const baseClass = 'form-header' + +type Props = { + description?: React.ReactNode | string + heading: string +} +export function FormHeader({ description, heading }: Props) { + if (!heading) { + return null + } + + return ( +
+

{heading}

+ {Boolean(description) &&

{description}

} +
+ ) +} diff --git a/packages/next/src/routes/rest/auth/login.ts b/packages/next/src/routes/rest/auth/login.ts index 5714c023d..f9f046c0d 100644 --- a/packages/next/src/routes/rest/auth/login.ts +++ b/packages/next/src/routes/rest/auth/login.ts @@ -29,8 +29,8 @@ export const login: CollectionRouteHandler = async ({ collection, req }) => { }) const cookie = generatePayloadCookie({ - collectionConfig: collection.config, - payload: req.payload, + collectionAuthConfig: collection.config.auth, + cookiePrefix: req.payload.config.cookiePrefix, token: result.token, }) diff --git a/packages/next/src/routes/rest/auth/logout.ts b/packages/next/src/routes/rest/auth/logout.ts index e27c31990..cc49b48b2 100644 --- a/packages/next/src/routes/rest/auth/logout.ts +++ b/packages/next/src/routes/rest/auth/logout.ts @@ -30,8 +30,9 @@ export const logout: CollectionRouteHandler = async ({ collection, req }) => { } const expiredCookie = generateExpiredPayloadCookie({ - collectionConfig: collection.config, - payload: req.payload, + collectionAuthConfig: collection.config.auth, + config: req.payload.config, + cookiePrefix: req.payload.config.cookiePrefix, }) headers.set('Set-Cookie', expiredCookie) diff --git a/packages/next/src/routes/rest/auth/refresh.ts b/packages/next/src/routes/rest/auth/refresh.ts index 9c77ca90c..abf446cff 100644 --- a/packages/next/src/routes/rest/auth/refresh.ts +++ b/packages/next/src/routes/rest/auth/refresh.ts @@ -20,8 +20,8 @@ export const refresh: CollectionRouteHandler = async ({ collection, req }) => { if (result.setCookie) { const cookie = generatePayloadCookie({ - collectionConfig: collection.config, - payload: req.payload, + collectionAuthConfig: collection.config.auth, + cookiePrefix: req.payload.config.cookiePrefix, token: result.refreshedToken, }) diff --git a/packages/next/src/routes/rest/auth/registerFirstUser.ts b/packages/next/src/routes/rest/auth/registerFirstUser.ts index 7743ce79a..47995f825 100644 --- a/packages/next/src/routes/rest/auth/registerFirstUser.ts +++ b/packages/next/src/routes/rest/auth/registerFirstUser.ts @@ -28,8 +28,8 @@ export const registerFirstUser: CollectionRouteHandler = async ({ collection, re }) const cookie = generatePayloadCookie({ - collectionConfig: collection.config, - payload: req.payload, + collectionAuthConfig: collection.config.auth, + cookiePrefix: req.payload.config.cookiePrefix, token: result.token, }) diff --git a/packages/next/src/routes/rest/auth/resetPassword.ts b/packages/next/src/routes/rest/auth/resetPassword.ts index b32ae23e5..4cf7bbe1c 100644 --- a/packages/next/src/routes/rest/auth/resetPassword.ts +++ b/packages/next/src/routes/rest/auth/resetPassword.ts @@ -20,8 +20,8 @@ export const resetPassword: CollectionRouteHandler = async ({ collection, req }) }) const cookie = generatePayloadCookie({ - collectionConfig: collection.config, - payload: req.payload, + collectionAuthConfig: collection.config.auth, + cookiePrefix: req.payload.config.cookiePrefix, token: result.token, }) diff --git a/packages/next/src/utilities/initPage/handleAdminPage.ts b/packages/next/src/utilities/initPage/handleAdminPage.ts index 24868a322..5ef40467f 100644 --- a/packages/next/src/utilities/initPage/handleAdminPage.ts +++ b/packages/next/src/utilities/initPage/handleAdminPage.ts @@ -1,25 +1,21 @@ -import type { - Permissions, - SanitizedCollectionConfig, - SanitizedConfig, - SanitizedGlobalConfig, -} from 'payload' +import type { SanitizedCollectionConfig, SanitizedConfig, SanitizedGlobalConfig } from 'payload' -import { notFound } from 'next/navigation.js' +import { getRouteWithoutAdmin, isAdminRoute } from './shared.js' -import { getRouteWithoutAdmin, isAdminAuthRoute, isAdminRoute } from './shared.js' - -export const handleAdminPage = ({ - adminRoute, - config, - permissions, - route, -}: { +type Args = { adminRoute: string config: SanitizedConfig - permissions: Permissions route: string -}) => { +} +type RouteInfo = { + collectionConfig?: SanitizedCollectionConfig + collectionSlug?: string + docID?: string + globalConfig?: SanitizedGlobalConfig + globalSlug?: string +} + +export function getRouteInfo({ adminRoute, config, route }: Args): RouteInfo { if (isAdminRoute({ adminRoute, config, route })) { const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route }) const routeSegments = routeWithoutAdmin.split('/').filter(Boolean) @@ -33,28 +29,18 @@ export const handleAdminPage = ({ if (collectionSlug) { collectionConfig = config.collections.find((collection) => collection.slug === collectionSlug) - - if (!collectionConfig) { - notFound() - } } if (globalSlug) { globalConfig = config.globals.find((global) => global.slug === globalSlug) - - if (!globalConfig) { - notFound() - } - } - - if (!permissions.canAccessAdmin && !isAdminAuthRoute({ adminRoute, config, route })) { - notFound() } return { collectionConfig, + collectionSlug, docID, globalConfig, + globalSlug, } } diff --git a/packages/next/src/utilities/initPage/handleAuthRedirect.ts b/packages/next/src/utilities/initPage/handleAuthRedirect.ts index 20393b698..bba32ae47 100644 --- a/packages/next/src/utilities/initPage/handleAuthRedirect.ts +++ b/packages/next/src/utilities/initPage/handleAuthRedirect.ts @@ -1,57 +1,46 @@ +import type { User } from 'payload' + import { formatAdminURL } from '@payloadcms/ui/shared' -import { redirect } from 'next/navigation.js' import * as qs from 'qs-esm' -import { isAdminAuthRoute, isAdminRoute } from './shared.js' - -export const handleAuthRedirect = ({ - config, - redirectUnauthenticatedUser, - route, - searchParams, -}: { +type Args = { config - redirectUnauthenticatedUser: boolean | string route: string searchParams: { [key: string]: string | string[] } -}) => { + user?: User +} +export const handleAuthRedirect = ({ config, route, searchParams, user }: Args): string => { const { admin: { - routes: { login: loginRouteFromConfig }, + routes: { login: loginRouteFromConfig, unauthorized: unauthorizedRoute }, }, routes: { admin: adminRoute }, } = config - if (!isAdminAuthRoute({ adminRoute, config, route })) { - if (searchParams && 'redirect' in searchParams) { - delete searchParams.redirect - } - - const redirectRoute = encodeURIComponent( - route + Object.keys(searchParams ?? {}).length - ? `${qs.stringify(searchParams, { addQueryPrefix: true })}` - : undefined, - ) - - const adminLoginRoute = formatAdminURL({ adminRoute, path: loginRouteFromConfig }) - - const customLoginRoute = - typeof redirectUnauthenticatedUser === 'string' ? redirectUnauthenticatedUser : undefined - - const loginRoute = isAdminRoute({ adminRoute, config, route }) - ? adminLoginRoute - : customLoginRoute || loginRouteFromConfig - - const parsedLoginRouteSearchParams = qs.parse(loginRoute.split('?')[1] ?? '') - - const searchParamsWithRedirect = `${qs.stringify( - { - ...parsedLoginRouteSearchParams, - ...(redirectRoute ? { redirect: redirectRoute } : {}), - }, - { addQueryPrefix: true }, - )}` - - redirect(`${loginRoute.split('?')[0]}${searchParamsWithRedirect}`) + if (searchParams && 'redirect' in searchParams) { + delete searchParams.redirect } + + const redirectRoute = encodeURIComponent( + route + Object.keys(searchParams ?? {}).length + ? `${qs.stringify(searchParams, { addQueryPrefix: true })}` + : undefined, + ) + + const redirectTo = formatAdminURL({ + adminRoute, + path: user ? unauthorizedRoute : loginRouteFromConfig, + }) + + const parsedLoginRouteSearchParams = qs.parse(redirectTo.split('?')[1] ?? '') + + const searchParamsWithRedirect = `${qs.stringify( + { + ...parsedLoginRouteSearchParams, + ...(redirectRoute ? { redirect: redirectRoute } : {}), + }, + { addQueryPrefix: true }, + )}` + + return `${redirectTo.split('?')[0]}${searchParamsWithRedirect}` } diff --git a/packages/next/src/utilities/initPage/index.ts b/packages/next/src/utilities/initPage/index.ts index ff2ef34a2..fb402c3ab 100644 --- a/packages/next/src/utilities/initPage/index.ts +++ b/packages/next/src/utilities/initPage/index.ts @@ -2,6 +2,7 @@ import type { InitPageResult, Locale, PayloadRequest, VisibleEntities } from 'pa import { findLocaleFromCode } from '@payloadcms/ui/shared' import { headers as getHeaders } from 'next/headers.js' +import { notFound } from 'next/navigation.js' import { createLocalReq, isEntityHidden, parseCookies } from 'payload' import * as qs from 'qs-esm' @@ -9,13 +10,13 @@ import type { Args } from './types.js' import { getPayloadHMR } from '../getPayloadHMR.js' import { initReq } from '../initReq.js' -import { handleAdminPage } from './handleAdminPage.js' +import { getRouteInfo } from './handleAdminPage.js' import { handleAuthRedirect } from './handleAuthRedirect.js' +import { isPublicAdminRoute } from './shared.js' export const initPage = async ({ config: configPromise, importMap, - redirectUnauthenticatedUser = false, route, searchParams, }: Args): Promise => { @@ -128,22 +129,30 @@ export const initPage = async ({ .filter(Boolean), } - if (redirectUnauthenticatedUser && !user) { - handleAuthRedirect({ + let redirectTo = null + + if ( + !permissions.canAccessAdmin && + !isPublicAdminRoute({ adminRoute, config: payload.config, route }) + ) { + redirectTo = handleAuthRedirect({ config: payload.config, - redirectUnauthenticatedUser, route, searchParams, + user, }) } - const { collectionConfig, docID, globalConfig } = handleAdminPage({ + const { collectionConfig, collectionSlug, docID, globalConfig, globalSlug } = getRouteInfo({ adminRoute, config: payload.config, - permissions, route, }) + if ((collectionSlug && !collectionConfig) || (globalSlug && !globalConfig)) { + return notFound() + } + return { collectionConfig, cookies, @@ -152,6 +161,7 @@ export const initPage = async ({ languageOptions, locale, permissions, + redirectTo, req, translations: i18n.translations, visibleEntities, diff --git a/packages/next/src/utilities/initPage/shared.ts b/packages/next/src/utilities/initPage/shared.ts index 986f573cd..185d7ad7b 100644 --- a/packages/next/src/utilities/initPage/shared.ts +++ b/packages/next/src/utilities/initPage/shared.ts @@ -1,6 +1,10 @@ import type { SanitizedConfig } from 'payload' -const authRouteKeys: (keyof SanitizedConfig['admin']['routes'])[] = [ +// Routes that require admin authentication +const publicAdminRoutes: (keyof Pick< + SanitizedConfig['admin']['routes'], + 'createFirstUser' | 'forgot' | 'inactivity' | 'login' | 'logout' | 'reset' | 'unauthorized' +>)[] = [ 'createFirstUser', 'forgot', 'login', @@ -13,17 +17,16 @@ const authRouteKeys: (keyof SanitizedConfig['admin']['routes'])[] = [ export const isAdminRoute = ({ adminRoute, - config, route, }: { adminRoute: string config: SanitizedConfig route: string }): boolean => { - return route.startsWith(adminRoute) && !isAdminAuthRoute({ adminRoute, config, route }) + return route.startsWith(adminRoute) } -export const isAdminAuthRoute = ({ +export const isPublicAdminRoute = ({ adminRoute, config, route, @@ -32,13 +35,17 @@ export const isAdminAuthRoute = ({ config: SanitizedConfig route: string }): boolean => { - const authRoutes = config.admin?.routes - ? Object.entries(config.admin.routes) - .filter(([key]) => authRouteKeys.includes(key as keyof SanitizedConfig['admin']['routes'])) - .map(([_, value]) => value) - : [] - - return authRoutes.some((r) => getRouteWithoutAdmin({ adminRoute, route }).startsWith(r)) + return publicAdminRoutes.some((routeSegment) => { + const segment = config.admin?.routes?.[routeSegment] || routeSegment + const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route }) + if (routeWithoutAdmin.startsWith(segment)) { + return true + } else if (routeWithoutAdmin.includes('/verify/')) { + return true + } else { + return false + } + }) } export const getRouteWithoutAdmin = ({ diff --git a/packages/next/src/views/ForgotPassword/ForgotPasswordForm/index.tsx b/packages/next/src/views/ForgotPassword/ForgotPasswordForm/index.tsx index 8c1b15496..c5f4833fa 100644 --- a/packages/next/src/views/ForgotPassword/ForgotPasswordForm/index.tsx +++ b/packages/next/src/views/ForgotPassword/ForgotPasswordForm/index.tsx @@ -5,7 +5,9 @@ import type { FormState, PayloadRequest } from 'payload' import { EmailField, Form, FormSubmit, TextField, useConfig, useTranslation } from '@payloadcms/ui' import { email, text } from 'payload/shared' -import React, { Fragment, useState } from 'react' +import React, { useState } from 'react' + +import { FormHeader } from '../../../elements/FormHeader/index.js' export const ForgotPasswordForm: React.FC = () => { const { config } = useConfig() @@ -54,10 +56,10 @@ export const ForgotPasswordForm: React.FC = () => { if (hasSubmitted) { return ( - -

{t('authentication:emailSent')}

-

{t('authentication:checkYourEmailForPasswordReset')}

-
+ ) } @@ -68,12 +70,14 @@ export const ForgotPasswordForm: React.FC = () => { initialState={initialState} method="POST" > -

{t('authentication:forgotPassword')}

-

- {loginWithUsername - ? t('authentication:forgotPasswordUsernameInstructions') - : t('authentication:forgotPasswordEmailInstructions')} -

+ {loginWithUsername ? ( { } /> )} - {t('general:submit')} + {t('general:submit')} ) } diff --git a/packages/next/src/views/ForgotPassword/index.tsx b/packages/next/src/views/ForgotPassword/index.tsx index 108638df0..ec154248d 100644 --- a/packages/next/src/views/ForgotPassword/index.tsx +++ b/packages/next/src/views/ForgotPassword/index.tsx @@ -5,6 +5,7 @@ import { formatAdminURL, Translation } from '@payloadcms/ui/shared' import LinkImport from 'next/link.js' import React, { Fragment } from 'react' +import { FormHeader } from '../../elements/FormHeader/index.js' import { ForgotPasswordForm } from './ForgotPasswordForm/index.js' export { generateForgotPasswordMetadata } from './meta.js' @@ -31,26 +32,27 @@ export const ForgotPasswordView: React.FC = ({ initPageResult }) if (user) { return ( -

{i18n.t('authentication:alreadyLoggedIn')}

-

- ( - - {children} - - ), - }} - i18nKey="authentication:loggedInChangePassword" - t={i18n.t} - /> -

-
+ ( + + {children} + + ), + }} + i18nKey="authentication:loggedInChangePassword" + t={i18n.t} + /> + } + heading={i18n.t('authentication:alreadyLoggedIn')} + /> diff --git a/packages/next/src/views/ResetPassword/index.client.tsx b/packages/next/src/views/ResetPassword/ResetPasswordForm/index.tsx similarity index 71% rename from packages/next/src/views/ResetPassword/index.client.tsx rename to packages/next/src/views/ResetPassword/ResetPasswordForm/index.tsx index 6128de4c9..c0af119d6 100644 --- a/packages/next/src/views/ResetPassword/index.client.tsx +++ b/packages/next/src/views/ResetPassword/ResetPasswordForm/index.tsx @@ -1,6 +1,4 @@ 'use client' -import type { FormState } from 'payload' - import { ConfirmPasswordField, Form, @@ -13,8 +11,8 @@ import { } from '@payloadcms/ui' import { formatAdminURL } from '@payloadcms/ui/shared' import { useRouter } from 'next/navigation.js' +import { type FormState } from 'payload' import React from 'react' -import { toast } from 'sonner' type Args = { readonly token: string @@ -33,7 +31,7 @@ const initialState: FormState = { }, } -export const ResetPasswordClient: React.FC = ({ token }) => { +export const ResetPasswordForm: React.FC = ({ token }) => { const i18n = useTranslation() const { config: { @@ -47,26 +45,21 @@ export const ResetPasswordClient: React.FC = ({ token }) => { } = useConfig() const history = useRouter() - const { fetchFullUser } = useAuth() - const onSuccess = React.useCallback( - async (data) => { - if (data.token) { - await fetchFullUser() - history.push(adminRoute) - } else { - history.push( - formatAdminURL({ - adminRoute, - path: loginRoute, - }), - ) - toast.success(i18n.t('general:updatedSuccessfully')) - } - }, - [adminRoute, fetchFullUser, history, i18n, loginRoute], - ) + const onSuccess = React.useCallback(async () => { + const user = await fetchFullUser() + if (user) { + history.push(adminRoute) + } else { + history.push( + formatAdminURL({ + adminRoute, + path: loginRoute, + }), + ) + } + }, [adminRoute, fetchFullUser, history, loginRoute]) return (
= ({ token }) => { method="POST" onSuccess={onSuccess} > -
+
form { - width: 100%; - - & > .inputWrap { - display: flex; - flex-direction: column; - gap: base(0.8); - - > * { - margin: 0; - } - } - } - - & > .btn { - margin: 0; - } } } } diff --git a/packages/next/src/views/ResetPassword/index.tsx b/packages/next/src/views/ResetPassword/index.tsx index 4b25efbb9..0ddc1f05e 100644 --- a/packages/next/src/views/ResetPassword/index.tsx +++ b/packages/next/src/views/ResetPassword/index.tsx @@ -5,8 +5,9 @@ import { formatAdminURL, Translation } from '@payloadcms/ui/shared' import LinkImport from 'next/link.js' import React from 'react' -import { ResetPasswordClient } from './index.client.js' +import { FormHeader } from '../../elements/FormHeader/index.js' import './index.scss' +import { ResetPasswordForm } from './ResetPasswordForm/index.js' export const resetPasswordBaseClass = 'reset-password' @@ -29,7 +30,7 @@ export const ResetPassword: React.FC = ({ initPageResult, params const { admin: { - routes: { account: accountRoute }, + routes: { account: accountRoute, login: loginRoute }, }, routes: { admin: adminRoute }, } = config @@ -37,25 +38,27 @@ export const ResetPassword: React.FC = ({ initPageResult, params if (user) { return (
-

{i18n.t('authentication:alreadyLoggedIn')}

-

- ( - - {children} - - ), - }} - i18nKey="authentication:loggedInChangePassword" - t={i18n.t} - /> -

+ ( + + {children} + + ), + }} + i18nKey="authentication:loggedInChangePassword" + t={i18n.t} + /> + } + heading={i18n.t('authentication:alreadyLoggedIn')} + /> @@ -65,8 +68,16 @@ export const ResetPassword: React.FC = ({ initPageResult, params return (
-

{i18n.t('authentication:resetPassword')}

- + + + + {i18n.t('authentication:backToLogin')} +
) } diff --git a/packages/next/src/views/Root/getViewFromConfig.ts b/packages/next/src/views/Root/getViewFromConfig.ts index 2185948f3..b7851ca39 100644 --- a/packages/next/src/views/Root/getViewFromConfig.ts +++ b/packages/next/src/views/Root/getViewFromConfig.ts @@ -92,7 +92,6 @@ export const getViewFromConfig = ({ } templateClassName = 'dashboard' templateType = 'default' - initPageOptions.redirectUnauthenticatedUser = true } break } @@ -132,7 +131,6 @@ export const getViewFromConfig = ({ templateType = 'minimal' if (viewKey === 'account') { - initPageOptions.redirectUnauthenticatedUser = true templateType = 'default' } } @@ -150,7 +148,6 @@ export const getViewFromConfig = ({ if (isCollection) { // --> /collections/:collectionSlug - initPageOptions.redirectUnauthenticatedUser = true ViewToRender = { Component: ListView, @@ -160,7 +157,6 @@ export const getViewFromConfig = ({ templateType = 'default' } else if (isGlobal) { // --> /globals/:globalSlug - initPageOptions.redirectUnauthenticatedUser = true ViewToRender = { Component: DocumentView, @@ -187,7 +183,6 @@ export const getViewFromConfig = ({ // --> /collections/:collectionSlug/:id/versions // --> /collections/:collectionSlug/:id/versions/:versionId // --> /collections/:collectionSlug/:id/api - initPageOptions.redirectUnauthenticatedUser = true ViewToRender = { Component: DocumentView, @@ -201,7 +196,6 @@ export const getViewFromConfig = ({ // --> /globals/:globalSlug/preview // --> /globals/:globalSlug/versions/:versionId // --> /globals/:globalSlug/api - initPageOptions.redirectUnauthenticatedUser = true ViewToRender = { Component: DocumentView, diff --git a/packages/next/src/views/Root/index.tsx b/packages/next/src/views/Root/index.tsx index 7a9ed17e5..db3cfa53c 100644 --- a/packages/next/src/views/Root/index.tsx +++ b/packages/next/src/views/Root/index.tsx @@ -72,6 +72,10 @@ export const RootPage = async ({ const initPageResult = await initPage(initPageOptions) + if (typeof initPageResult?.redirectTo === 'string') { + redirect(initPageResult.redirectTo) + } + if (initPageResult) { dbHasUser = await initPageResult?.req.payload.db .findOne({ @@ -137,8 +141,8 @@ export const RootPage = async ({ visibleEntities={{ // The reason we are not passing in initPageResult.visibleEntities directly is due to a "Cannot assign to read only property of object '#" error introduced in React 19 // which this caused as soon as initPageResult.visibleEntities is passed in - collections: initPageResult.visibleEntities?.collections, - globals: initPageResult.visibleEntities?.globals, + collections: initPageResult?.visibleEntities?.collections, + globals: initPageResult?.visibleEntities?.globals, }} > {RenderedView} diff --git a/packages/next/src/views/Unauthorized/index.scss b/packages/next/src/views/Unauthorized/index.scss index 697c9b997..125ffe9e0 100644 --- a/packages/next/src/views/Unauthorized/index.scss +++ b/packages/next/src/views/Unauthorized/index.scss @@ -2,37 +2,8 @@ @layer payload-default { .unauthorized { - margin-top: var(--base); - - & > * { - &:first-child { - margin-top: 0; - } - &:last-child { - margin-bottom: 0; - } - } - &__button { margin: 0; } - - &--margin-top-large { - margin-top: calc(var(--base) * 2); - } - - @include large-break { - &--margin-top-large { - margin-top: var(--base); - } - } - - @include small-break { - margin-top: calc(var(--base) / 2); - - &--margin-top-large { - margin-top: calc(var(--base) / 2); - } - } } } diff --git a/packages/next/src/views/Unauthorized/index.tsx b/packages/next/src/views/Unauthorized/index.tsx index 294015624..5ace45cf2 100644 --- a/packages/next/src/views/Unauthorized/index.tsx +++ b/packages/next/src/views/Unauthorized/index.tsx @@ -1,9 +1,11 @@ import type { AdminViewComponent, PayloadServerReactComponent } from 'payload' -import { Button, Gutter } from '@payloadcms/ui' +import { Button } from '@payloadcms/ui' +import { formatAdminURL } from '@payloadcms/ui/shared' import LinkImport from 'next/link.js' import React from 'react' +import { FormHeader } from '../../elements/FormHeader/index.js' import './index.scss' const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default @@ -23,24 +25,31 @@ export const UnauthorizedView: PayloadServerReactComponent = admin: { routes: { logout: logoutRoute }, }, + routes: { admin: adminRoute }, }, }, }, } = initPageResult return ( - -

{i18n.t('error:unauthorized')}

-

{i18n.t('error:notAllowedToAccessPage')}

+
+ + - +
) } diff --git a/packages/next/src/views/Verify/index.client.tsx b/packages/next/src/views/Verify/index.client.tsx new file mode 100644 index 000000000..889e3bf38 --- /dev/null +++ b/packages/next/src/views/Verify/index.client.tsx @@ -0,0 +1,32 @@ +'use client' +import { toast } from '@payloadcms/ui' +import { useRouter } from 'next/navigation.js' +import React, { useEffect } from 'react' + +type Props = { + message: string + redirectTo: string +} +export function ToastAndRedirect({ message, redirectTo }: Props) { + const router = useRouter() + const hasToastedRef = React.useRef(false) + + useEffect(() => { + let timeoutID + if (toast) { + timeoutID = setTimeout(() => { + toast.success(message) + hasToastedRef.current = true + router.push(redirectTo) + }, 100) + } + + return () => { + if (timeoutID) { + clearTimeout(timeoutID) + } + } + }, [router, redirectTo, message]) + + return null +} diff --git a/packages/next/src/views/Verify/index.tsx b/packages/next/src/views/Verify/index.tsx index 19edad0c8..cee82f0e8 100644 --- a/packages/next/src/views/Verify/index.tsx +++ b/packages/next/src/views/Verify/index.tsx @@ -1,10 +1,10 @@ import type { AdminViewProps } from 'payload' import { formatAdminURL } from '@payloadcms/ui/shared' -import { redirect } from 'next/navigation.js' import React from 'react' import { Logo } from '../../elements/Logo/index.js' +import { ToastAndRedirect } from './index.client.js' import './index.scss' export const verifyBaseClass = 'verify' @@ -33,6 +33,7 @@ export const Verify: React.FC = async ({ } = config let textToRender + let isVerified = false try { await req.payload.verifyEmail({ @@ -40,15 +41,21 @@ export const Verify: React.FC = async ({ token, }) - return redirect(formatAdminURL({ adminRoute, path: '/login' })) + isVerified = true + textToRender = req.t('authentication:emailVerified') } catch (e) { - // already verified - if (e?.status === 202) { - redirect(formatAdminURL({ adminRoute, path: '/login' })) - } textToRender = req.t('authentication:unableToVerify') } + if (isVerified) { + return ( + + ) + } + return (
diff --git a/packages/payload/src/admin/views/types.ts b/packages/payload/src/admin/views/types.ts index 85650010b..cda94b478 100644 --- a/packages/payload/src/admin/views/types.ts +++ b/packages/payload/src/admin/views/types.ts @@ -53,6 +53,7 @@ export type InitPageResult = { languageOptions: LanguageOptions locale?: Locale permissions: Permissions + redirectTo?: string req: PayloadRequest translations: ClientTranslationsObject visibleEntities: VisibleEntities diff --git a/packages/payload/src/auth/cookies.ts b/packages/payload/src/auth/cookies.ts index 31d6f24c0..67e69dfdb 100644 --- a/packages/payload/src/auth/cookies.ts +++ b/packages/payload/src/auth/cookies.ts @@ -1,4 +1,3 @@ -import type { Payload } from '../index.js' import type { SanitizedCollectionConfig } from './../collections/config/types.js' type CookieOptions = { @@ -125,63 +124,63 @@ export const getCookieExpiration = ({ seconds = 7200 }: GetCookieExpirationArgs) type GeneratePayloadCookieArgs = { /* The auth collection config */ - collectionConfig: SanitizedCollectionConfig - /* An instance of payload */ - payload: Payload + collectionAuthConfig: SanitizedCollectionConfig['auth'] + /* Prefix to scope the cookie */ + cookiePrefix: string /* The returnAs value */ returnCookieAsObject?: boolean /* The token to be stored in the cookie */ token: string } export const generatePayloadCookie = ({ - collectionConfig, - payload, + collectionAuthConfig, + cookiePrefix, returnCookieAsObject = false, token, }: T): T['returnCookieAsObject'] extends true ? CookieObject : string => { const sameSite = - typeof collectionConfig.auth.cookies.sameSite === 'string' - ? collectionConfig.auth.cookies.sameSite - : collectionConfig.auth.cookies.sameSite + typeof collectionAuthConfig.cookies.sameSite === 'string' + ? collectionAuthConfig.cookies.sameSite + : collectionAuthConfig.cookies.sameSite ? 'Strict' : undefined return generateCookie({ - name: `${payload.config.cookiePrefix}-token`, - domain: collectionConfig.auth.cookies.domain ?? undefined, - expires: getCookieExpiration({ seconds: collectionConfig.auth.tokenExpiration }), + name: `${cookiePrefix}-token`, + domain: collectionAuthConfig.cookies.domain ?? undefined, + expires: getCookieExpiration({ seconds: collectionAuthConfig.tokenExpiration }), httpOnly: true, path: '/', returnCookieAsObject, sameSite, - secure: collectionConfig.auth.cookies.secure, + secure: collectionAuthConfig.cookies.secure, value: token, }) } export const generateExpiredPayloadCookie = >({ - collectionConfig, - payload, + collectionAuthConfig, + cookiePrefix, returnCookieAsObject = false, }: T): T['returnCookieAsObject'] extends true ? CookieObject : string => { const sameSite = - typeof collectionConfig.auth.cookies.sameSite === 'string' - ? collectionConfig.auth.cookies.sameSite - : collectionConfig.auth.cookies.sameSite + typeof collectionAuthConfig.cookies.sameSite === 'string' + ? collectionAuthConfig.cookies.sameSite + : collectionAuthConfig.cookies.sameSite ? 'Strict' : undefined const expires = new Date(Date.now() - 1000) return generateCookie({ - name: `${payload.config.cookiePrefix}-token`, - domain: collectionConfig.auth.cookies.domain ?? undefined, + name: `${cookiePrefix}-token`, + domain: collectionAuthConfig.cookies.domain ?? undefined, expires, httpOnly: true, path: '/', returnCookieAsObject, sameSite, - secure: collectionConfig.auth.cookies.secure, + secure: collectionAuthConfig.cookies.secure, }) } diff --git a/packages/payload/src/auth/operations/resetPassword.ts b/packages/payload/src/auth/operations/resetPassword.ts index ac430e42a..ea31e5512 100644 --- a/packages/payload/src/auth/operations/resetPassword.ts +++ b/packages/payload/src/auth/operations/resetPassword.ts @@ -81,7 +81,7 @@ export const resetPasswordOperation = async (args: Arguments): Promise = user.resetPasswordExpiration = new Date().toISOString() if (collectionConfig.auth.verify) { - user._verified = true + user._verified = Boolean(user._verified) } const doc = await payload.db.updateOne({ diff --git a/packages/payload/src/auth/operations/verifyEmail.ts b/packages/payload/src/auth/operations/verifyEmail.ts index 0ae94c1f1..fff5d842e 100644 --- a/packages/payload/src/auth/operations/verifyEmail.ts +++ b/packages/payload/src/auth/operations/verifyEmail.ts @@ -34,9 +34,6 @@ export const verifyEmailOperation = async (args: Args): Promise => { if (!user) { throw new APIError('Verification token is invalid.', httpStatus.FORBIDDEN) } - if (user && user._verified === true) { - throw new APIError('This account has already been activated.', httpStatus.ACCEPTED) - } await req.payload.db.updateOne({ id: user.id, diff --git a/packages/payload/src/exports/shared.ts b/packages/payload/src/exports/shared.ts index 74fcb9ef4..510c6dc98 100644 --- a/packages/payload/src/exports/shared.ts +++ b/packages/payload/src/exports/shared.ts @@ -1,5 +1,13 @@ +export { + generateCookie, + generateExpiredPayloadCookie, + generatePayloadCookie, + getCookieExpiration, + parseCookies, +} from '../auth/cookies.js' export { parsePayloadComponent } from '../bin/generateImportMap/parsePayloadComponent.js' export { defaults as collectionDefaults } from '../collections/config/defaults.js' + export { serverProps } from '../config/types.js' export { @@ -20,19 +28,19 @@ export { tabHasName, valueIsValueWithRelation, } from '../fields/config/types.js' - export * from '../fields/validations.js' + export { validOperators } from '../types/constants.js' export { formatFilesize } from '../uploads/formatFilesize.js' export { isImage } from '../uploads/isImage.js' - export { deepCopyObject, deepCopyObjectComplex, deepCopyObjectSimple, } from '../utilities/deepCopyObject.js' + export { deepMerge, deepMergeWithCombinedArrays, @@ -41,8 +49,8 @@ export { } from '../utilities/deepMerge.js' export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON.js' - export { getDataByPath } from '../utilities/getDataByPath.js' + export { getSiblingData } from '../utilities/getSiblingData.js' export { getUniqueListBy } from '../utilities/getUniqueListBy.js' @@ -66,6 +74,5 @@ export { unflatten } from '../utilities/unflatten.js' export { wait } from '../utilities/wait.js' export { default as wordBoundariesRegex } from '../utilities/wordBoundariesRegex.js' - export { versionDefaults } from '../versions/defaults.js' export { deepMergeSimple } from '@payloadcms/translations/utilities' diff --git a/packages/translations/src/languages/ar.ts b/packages/translations/src/languages/ar.ts index 9fc249f6c..f3e355cef 100644 --- a/packages/translations/src/languages/ar.ts +++ b/packages/translations/src/languages/ar.ts @@ -184,7 +184,7 @@ export const arTranslations: DefaultTranslationsObject = { backToDashboard: 'العودة للوحة التّحكّم', cancel: 'إلغاء', changesNotSaved: 'لم يتمّ حفظ التّغييرات. إن غادرت الآن ، ستفقد تغييراتك.', - clearAll: undefined, + clearAll: 'امسح الكل', close: 'إغلاق', collapse: 'طيّ', collections: 'المجموعات', @@ -407,7 +407,7 @@ export const arTranslations: DefaultTranslationsObject = { lastSavedAgo: 'تم الحفظ آخر مرة قبل {{distance}}', noFurtherVersionsFound: 'لم يتمّ العثور على نسخات أخرى', noRowsFound: 'لم يتمّ العثور على {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'لم يتم اختيار {{label}}', preview: 'معاينة', previouslyPublished: 'نشر سابقا', problemRestoringVersion: 'حدث خطأ في استعادة هذه النّسخة', diff --git a/packages/translations/src/languages/az.ts b/packages/translations/src/languages/az.ts index 14dd92721..f60668c88 100644 --- a/packages/translations/src/languages/az.ts +++ b/packages/translations/src/languages/az.ts @@ -186,7 +186,7 @@ export const azTranslations: DefaultTranslationsObject = { cancel: 'Ləğv et', changesNotSaved: 'Dəyişiklikləriniz saxlanılmayıb. İndi çıxsanız, dəyişikliklərinizi itirəcəksiniz.', - clearAll: undefined, + clearAll: 'Hamısını təmizlə', close: 'Bağla', collapse: 'Bağla', collections: 'Kolleksiyalar', @@ -414,7 +414,7 @@ export const azTranslations: DefaultTranslationsObject = { lastSavedAgo: '{{distance}} əvvəl son yadda saxlanıldı', noFurtherVersionsFound: 'Başqa versiyalar tapılmadı', noRowsFound: 'Heç bir {{label}} tapılmadı', - noRowsSelected: undefined, + noRowsSelected: 'Heç bir {{label}} seçilməyib', preview: 'Öncədən baxış', previouslyPublished: 'Daha əvvəl nəşr olunmuş', problemRestoringVersion: 'Bu versiyanın bərpasında problem yaşandı', diff --git a/packages/translations/src/languages/bg.ts b/packages/translations/src/languages/bg.ts index 83e684e35..1494370e2 100644 --- a/packages/translations/src/languages/bg.ts +++ b/packages/translations/src/languages/bg.ts @@ -185,7 +185,7 @@ export const bgTranslations: DefaultTranslationsObject = { backToDashboard: 'Обратно към таблото', cancel: 'Отмени', changesNotSaved: 'Промените ти не са запазени. Ако напуснеш сега, ще ги загубиш.', - clearAll: undefined, + clearAll: 'Изчисти всичко', close: 'Затвори', collapse: 'Свий', collections: 'Колекции', @@ -413,7 +413,7 @@ export const bgTranslations: DefaultTranslationsObject = { lastSavedAgo: 'последно запазено преди {{distance}}', noFurtherVersionsFound: 'Не са открити повече версии', noRowsFound: 'Не е открит {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Не е избран {{label}}', preview: 'Предварителен преглед', previouslyPublished: 'Предишно публикувано', problemRestoringVersion: 'Имаше проблем при възстановяването на тази версия', diff --git a/packages/translations/src/languages/cs.ts b/packages/translations/src/languages/cs.ts index 3da8072bd..5b83192f2 100644 --- a/packages/translations/src/languages/cs.ts +++ b/packages/translations/src/languages/cs.ts @@ -185,7 +185,7 @@ export const csTranslations: DefaultTranslationsObject = { backToDashboard: 'Zpět na nástěnku', cancel: 'Zrušit', changesNotSaved: 'Vaše změny nebyly uloženy. Pokud teď odejdete, ztratíte své změny.', - clearAll: undefined, + clearAll: 'Vymazat vše', close: 'Zavřít', collapse: 'Sbalit', collections: 'Kolekce', @@ -412,7 +412,7 @@ export const csTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Naposledy uloženo před {{distance}}', noFurtherVersionsFound: 'Nenalezeny další verze', noRowsFound: 'Nenalezen {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Nebyl vybrán žádný {{label}}', preview: 'Náhled', previouslyPublished: 'Dříve publikováno', problemRestoringVersion: 'Při obnovování této verze došlo k problému', diff --git a/packages/translations/src/languages/de.ts b/packages/translations/src/languages/de.ts index 3f9353b8c..5a94770b8 100644 --- a/packages/translations/src/languages/de.ts +++ b/packages/translations/src/languages/de.ts @@ -190,7 +190,7 @@ export const deTranslations: DefaultTranslationsObject = { cancel: 'Abbrechen', changesNotSaved: 'Deine Änderungen wurden nicht gespeichert. Wenn du diese Seite verlässt, gehen deine Änderungen verloren.', - clearAll: undefined, + clearAll: 'Alles löschen', close: 'Schließen', collapse: 'Einklappen', collections: 'Sammlungen', @@ -418,7 +418,7 @@ export const deTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Zuletzt vor {{distance}} gespeichert', noFurtherVersionsFound: 'Keine weiteren Versionen vorhanden', noRowsFound: 'Kein {{label}} gefunden', - noRowsSelected: undefined, + noRowsSelected: 'Kein {{label}} ausgewählt', preview: 'Vorschau', previouslyPublished: 'Zuvor Veröffentlicht', problemRestoringVersion: 'Es gab ein Problem bei der Wiederherstellung dieser Version', diff --git a/packages/translations/src/languages/en.ts b/packages/translations/src/languages/en.ts index 9b91245ae..312db967a 100644 --- a/packages/translations/src/languages/en.ts +++ b/packages/translations/src/languages/en.ts @@ -66,9 +66,8 @@ export const enTranslations = { successfullyRegisteredFirstUser: 'Successfully registered first user.', successfullyUnlocked: 'Successfully unlocked', tokenRefreshSuccessful: 'Token refresh successful.', - username: 'Username', - unableToVerify: 'Unable to Verify', + username: 'Username', verified: 'Verified', verifiedSuccessfully: 'Verified Successfully', verify: 'Verify', diff --git a/packages/translations/src/languages/es.ts b/packages/translations/src/languages/es.ts index 41e5d351f..fa123ff02 100644 --- a/packages/translations/src/languages/es.ts +++ b/packages/translations/src/languages/es.ts @@ -190,7 +190,7 @@ export const esTranslations: DefaultTranslationsObject = { cancel: 'Cancelar', changesNotSaved: 'Tus cambios no han sido guardados. Si te sales ahora, se perderán tus cambios.', - clearAll: undefined, + clearAll: 'Borrar todo', close: 'Cerrar', collapse: 'Colapsar', collections: 'Colecciones', @@ -418,7 +418,7 @@ export const esTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Guardado por última vez hace {{distance}}', noFurtherVersionsFound: 'No se encontraron más versiones', noRowsFound: 'No encontramos {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'No se ha seleccionado ninguna {{etiqueta}}', preview: 'Previsualizar', previouslyPublished: 'Publicado Anteriormente', problemRestoringVersion: 'Ocurrió un problema al restaurar esta versión', diff --git a/packages/translations/src/languages/fa.ts b/packages/translations/src/languages/fa.ts index e8360788d..49e61bb8e 100644 --- a/packages/translations/src/languages/fa.ts +++ b/packages/translations/src/languages/fa.ts @@ -185,7 +185,7 @@ export const faTranslations: DefaultTranslationsObject = { cancel: 'لغو', changesNotSaved: 'تغییرات شما ذخیره نشده، اگر این برگه را ترک کنید. تمام تغییرات از دست خواهد رفت.', - clearAll: undefined, + clearAll: 'همه را پاک کنید', close: 'بستن', collapse: 'بستن', collections: 'مجموعه‌ها', @@ -411,7 +411,7 @@ export const faTranslations: DefaultTranslationsObject = { lastSavedAgo: 'آخرین بار {{distance}} پیش ذخیره شد', noFurtherVersionsFound: 'نگارش دیگری یافت نشد', noRowsFound: 'هیچ {{label}} یافت نشد', - noRowsSelected: undefined, + noRowsSelected: 'هیچ {{label}} ای انتخاب نشده است', preview: 'پیش‌نمایش', previouslyPublished: 'قبلا منتشر شده', problemRestoringVersion: 'مشکلی در بازیابی این نگارش وجود دارد', diff --git a/packages/translations/src/languages/fr.ts b/packages/translations/src/languages/fr.ts index bdd460a90..14b38f6e8 100644 --- a/packages/translations/src/languages/fr.ts +++ b/packages/translations/src/languages/fr.ts @@ -193,7 +193,7 @@ export const frTranslations: DefaultTranslationsObject = { cancel: 'Annuler', changesNotSaved: 'Vos modifications n’ont pas été enregistrées. Vous perdrez vos modifications si vous quittez maintenant.', - clearAll: undefined, + clearAll: 'Tout effacer', close: 'Fermer', collapse: 'Réduire', collections: 'Collections', @@ -425,7 +425,7 @@ export const frTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Dernière sauvegarde il y a {{distance}}', noFurtherVersionsFound: 'Aucune autre version trouvée', noRowsFound: 'Aucun(e) {{label}} trouvé(e)', - noRowsSelected: undefined, + noRowsSelected: 'Aucune {{étiquette}} sélectionnée', preview: 'Aperçu', previouslyPublished: 'Précédemment publié', problemRestoringVersion: 'Un problème est survenu lors de la restauration de cette version', diff --git a/packages/translations/src/languages/he.ts b/packages/translations/src/languages/he.ts index 8a8c46ec8..1acdb4305 100644 --- a/packages/translations/src/languages/he.ts +++ b/packages/translations/src/languages/he.ts @@ -181,7 +181,7 @@ export const heTranslations: DefaultTranslationsObject = { backToDashboard: 'חזרה ללוח המחוונים', cancel: 'ביטול', changesNotSaved: 'השינויים שלך לא נשמרו. אם תצא כעת, תאבד את השינויים שלך.', - clearAll: undefined, + clearAll: 'נקה הכל', close: 'סגור', collapse: 'כווץ', collections: 'אוספים', @@ -260,7 +260,7 @@ export const heTranslations: DefaultTranslationsObject = { nothingFound: 'לא נמצא כלום', noValue: 'אין ערך', of: 'מתוך', - only: undefined, + only: 'רק', open: 'פתח', or: 'או', order: 'סדר', @@ -401,7 +401,7 @@ export const heTranslations: DefaultTranslationsObject = { lastSavedAgo: 'נשמר לאחרונה לפני {{distance}}', noFurtherVersionsFound: 'לא נמצאו עוד גרסאות', noRowsFound: 'לא נמצאו {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'לא נבחר {{תווית}}', preview: 'תצוגה מקדימה', previouslyPublished: 'פורסם בעבר', problemRestoringVersion: 'הייתה בעיה בשחזור הגרסה הזו', diff --git a/packages/translations/src/languages/hr.ts b/packages/translations/src/languages/hr.ts index 2fd03b066..3d60e3332 100644 --- a/packages/translations/src/languages/hr.ts +++ b/packages/translations/src/languages/hr.ts @@ -34,7 +34,6 @@ export const hrTranslations: DefaultTranslationsObject = { generateNewAPIKey: 'Generiraj novi API ključ', generatingNewAPIKeyWillInvalidate: 'Generiranje novog API ključa će <1>poništiti prethodni ključ. Jeste li sigurni da želite nastaviti?', - newAPIKeyGenerated: 'New API ključ generiran.', lockUntil: 'Zaključaj dok', logBackIn: 'Ponovno se prijavite', loggedIn: 'Za prijavu s drugim korisničkim računom potrebno je prvo <0>odjaviti se', @@ -53,7 +52,8 @@ export const hrTranslations: DefaultTranslationsObject = { logoutSuccessful: 'Odjava uspješna.', logoutUser: 'Odjava korisnika', newAccountCreated: - 'Novi račun je izrađen. Pristupite računu klikom na: {{serverURL}}. Molimo kliknite na sljedeću poveznicu ili zalijepite URL, koji se nalazi ispod, u preglednik da biste potvrdili svoju e-mail adresu: {{verificationURL}}
Nakon što potvrdite e-mail adresu, moći ćete se prijaviti.', + 'Novi račun je izrađen. Pristupite računu klikom na: {{serverURL}}. Molimo kliknite na sljedeću poveznicu ili zalijepite URL, koji se nalazi ispod, u preglednik da biste potvrdili svoju e-mail adresu: {{verificationURL}}
Nakon što potvrdite e-mail adresu, moći ćete se prijaviti.', + newAPIKeyGenerated: 'New API ključ generiran.', newPassword: 'Nova lozinka', passed: 'Autentifikacija je prošla', passwordResetSuccessfully: 'Lozinka uspješno resetirana.', @@ -111,11 +111,11 @@ export const hrTranslations: DefaultTranslationsObject = { problemUploadingFile: 'Došlo je do problema pri učitavanju datoteke.', tokenInvalidOrExpired: 'Token je neispravan ili je istekao.', tokenNotProvided: 'Token nije pružen.', - unPublishingDocument: 'Došlo je do problema pri poništavanju objave ovog dokumenta.', unableToDeleteCount: 'Nije moguće izbrisati {{count}} od {{total}} {{label}}.', unableToUpdateCount: 'Nije moguće ažurirati {{count}} od {{total}} {{label}}.', unauthorized: 'Neovlašteno, morate biti prijavljeni da biste uputili ovaj zahtjev.', unknown: 'Došlo je do nepoznate pogreške.', + unPublishingDocument: 'Došlo je do problema pri poništavanju objave ovog dokumenta.', unspecific: 'Došlo je do pogreške.', userEmailAlreadyRegistered: 'Korisnik s navedenom e-mail adresom je već registriran.', userLocked: 'Ovaj korisnik je zaključan zbog previše neuspješnih pokušaja prijave.', @@ -186,7 +186,7 @@ export const hrTranslations: DefaultTranslationsObject = { backToDashboard: 'Natrag na nadzornu ploču', cancel: 'Otkaži', changesNotSaved: 'Vaše promjene nisu spremljene. Ako izađete sada, izgubit ćete promjene.', - clearAll: undefined, + clearAll: 'Očisti sve', close: 'Zatvori', collapse: 'Sažmi', collections: 'Kolekcije', @@ -258,11 +258,12 @@ export const hrTranslations: DefaultTranslationsObject = { next: 'Sljedeće', noFiltersSet: 'Nema postavljenih filtera', noLabel: '', - notFound: 'Nije pronađeno', - nothingFound: 'Ništa nije pronađeno', none: 'Nijedan', noOptions: 'Nema opcija', - noResults: 'Nije pronađen nijedan {{label}}. Ili {{label}} još uvijek ne postoji ili nijedan od odgovara postavljenim filterima.', + noResults: + 'Nije pronađen nijedan {{label}}. Ili {{label}} još uvijek ne postoji ili nijedan od odgovara postavljenim filterima.', + notFound: 'Nije pronađeno', + nothingFound: 'Ništa nije pronađeno', noValue: 'Bez vrijednosti', of: 'od', only: 'Samo', @@ -410,14 +411,14 @@ export const hrTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Zadnji put spremljeno prije {{distance}', noFurtherVersionsFound: 'Nisu pronađene daljnje verzije', noRowsFound: '{{label}} nije pronađeno', - noRowsSelected: undefined, + noRowsSelected: 'Nije odabrana {{oznaka}}', preview: 'Pregled', previouslyPublished: 'Prethodno objavljeno', problemRestoringVersion: 'Nastao je problem pri vraćanju ove verzije', publish: 'Objaviti', publishChanges: 'Objavi promjene', published: 'Objavljeno', - publishIn: undefined, + publishIn: 'Objavi na {{locale}}', publishing: 'Objavljivanje', restoreAsDraft: 'Vrati kao skicu', restoredSuccessfully: 'Uspješno vraćeno.', diff --git a/packages/translations/src/languages/hu.ts b/packages/translations/src/languages/hu.ts index a779520eb..ebdc48713 100644 --- a/packages/translations/src/languages/hu.ts +++ b/packages/translations/src/languages/hu.ts @@ -188,7 +188,7 @@ export const huTranslations: DefaultTranslationsObject = { cancel: 'Mégsem', changesNotSaved: 'A módosítások nem lettek mentve. Ha most távozik, elveszíti a változtatásokat.', - clearAll: undefined, + clearAll: 'Törölj mindent', close: 'Bezárás', collapse: 'Összecsukás', collections: 'Gyűjtemények', @@ -418,7 +418,7 @@ export const huTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Utoljára mentve {{distance}} órája', noFurtherVersionsFound: 'További verziók nem találhatók', noRowsFound: 'Nem található {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Nincs {{címke}} kiválasztva', preview: 'Előnézet', previouslyPublished: 'Korábban Közzétéve', problemRestoringVersion: 'Hiba történt a verzió visszaállításakor', diff --git a/packages/translations/src/languages/it.ts b/packages/translations/src/languages/it.ts index 49288a272..de8a0d105 100644 --- a/packages/translations/src/languages/it.ts +++ b/packages/translations/src/languages/it.ts @@ -189,7 +189,7 @@ export const itTranslations: DefaultTranslationsObject = { backToDashboard: 'Torna alla Dashboard', cancel: 'Cancella', changesNotSaved: 'Le tue modifiche non sono state salvate. Se esci ora, verranno perse.', - clearAll: undefined, + clearAll: 'Cancella Tutto', close: 'Chiudere', collapse: 'Comprimi', collections: 'Collezioni', @@ -418,7 +418,7 @@ export const itTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Ultimo salvataggio {{distance}} fa', noFurtherVersionsFound: 'Non sono state trovate ulteriori versioni', noRowsFound: 'Nessun {{label}} trovato', - noRowsSelected: undefined, + noRowsSelected: 'Nessuna {{etichetta}} selezionata', preview: 'Anteprima', previouslyPublished: 'Precedentemente Pubblicato', problemRestoringVersion: 'Si è verificato un problema durante il ripristino di questa versione', diff --git a/packages/translations/src/languages/ja.ts b/packages/translations/src/languages/ja.ts index 3be5e90fe..98c1cb0b3 100644 --- a/packages/translations/src/languages/ja.ts +++ b/packages/translations/src/languages/ja.ts @@ -186,7 +186,7 @@ export const jaTranslations: DefaultTranslationsObject = { backToDashboard: 'ダッシュボードに戻る', cancel: 'キャンセル', changesNotSaved: '未保存の変更があります。このまま画面を離れると内容が失われます。', - clearAll: undefined, + clearAll: 'すべてクリア', close: '閉じる', collapse: '閉じる', collections: 'コレクション', @@ -412,7 +412,7 @@ export const jaTranslations: DefaultTranslationsObject = { lastSavedAgo: '{{distance}}前に最後に保存されました', noFurtherVersionsFound: 'その他のバージョンは見つかりませんでした。', noRowsFound: '{{label}} は未設定です', - noRowsSelected: undefined, + noRowsSelected: '選択された{{label}}はありません', preview: 'プレビュー', previouslyPublished: '以前に公開された', problemRestoringVersion: 'このバージョンの復元に問題がありました。', diff --git a/packages/translations/src/languages/ko.ts b/packages/translations/src/languages/ko.ts index 6d1c7a2eb..771d10066 100644 --- a/packages/translations/src/languages/ko.ts +++ b/packages/translations/src/languages/ko.ts @@ -185,7 +185,7 @@ export const koTranslations: DefaultTranslationsObject = { backToDashboard: '대시보드로 돌아가기', cancel: '취소', changesNotSaved: '변경 사항이 저장되지 않았습니다. 지금 떠나면 변경 사항을 잃게 됩니다.', - clearAll: undefined, + clearAll: '모두 지우기', close: '닫기', collapse: '접기', collections: '컬렉션', @@ -408,7 +408,7 @@ export const koTranslations: DefaultTranslationsObject = { lastSavedAgo: '마지막으로 저장한지 {{distance}} 전', noFurtherVersionsFound: '더 이상의 버전을 찾을 수 없습니다.', noRowsFound: '{{label}}을(를) 찾을 수 없음', - noRowsSelected: undefined, + noRowsSelected: '선택된 {{label}} 없음', preview: '미리보기', previouslyPublished: '이전에 발표된', problemRestoringVersion: '이 버전을 복원하는 중 문제가 발생했습니다.', diff --git a/packages/translations/src/languages/my.ts b/packages/translations/src/languages/my.ts index c957f98de..90896b726 100644 --- a/packages/translations/src/languages/my.ts +++ b/packages/translations/src/languages/my.ts @@ -188,7 +188,7 @@ export const myTranslations: DefaultTranslationsObject = { cancel: 'မလုပ်တော့ပါ။', changesNotSaved: 'သင်၏ပြောင်းလဲမှုများကို မသိမ်းဆည်းရသေးပါ။ ယခု စာမျက်နှာက ထွက်လိုက်ပါက သင်၏ပြောင်းလဲမှုများ အကုန် ဆုံးရှုံးသွားပါမည်။ အကုန်နော်။', - clearAll: undefined, + clearAll: 'အားလုံးကိုရှင်းလင်းပါ', close: 'ပိတ်', collapse: 'ခေါက်သိမ်းပါ။', collections: 'စုစည်းမှူများ', @@ -420,7 +420,7 @@ export const myTranslations: DefaultTranslationsObject = { lastSavedAgo: 'နောက်ဆုံး သိမ်းချက် {{distance}} ကြာပြီး', noFurtherVersionsFound: 'နောက်ထပ်ဗားရှင်းများ မတွေ့ပါ။', noRowsFound: '{{label}} အားမတွေ့ပါ။', - noRowsSelected: undefined, + noRowsSelected: 'Tiada {{label}} yang dipilih', preview: 'နမူနာပြရန်', previouslyPublished: 'တိုင်းရင်းသားထုတ်ဝေခဲ့', problemRestoringVersion: 'ဤဗားရှင်းကို ပြန်လည်ရယူရာတွင် ပြဿနာရှိနေသည်။', diff --git a/packages/translations/src/languages/nb.ts b/packages/translations/src/languages/nb.ts index 4e2cf2dc2..558d7e16c 100644 --- a/packages/translations/src/languages/nb.ts +++ b/packages/translations/src/languages/nb.ts @@ -186,7 +186,7 @@ export const nbTranslations: DefaultTranslationsObject = { cancel: 'Avbryt', changesNotSaved: 'Endringene dine er ikke lagret. Hvis du forlater nå, vil du miste endringene dine.', - clearAll: undefined, + clearAll: 'Tøm alt', close: 'Lukk', collapse: 'Skjul', collections: 'Samlinger', @@ -266,7 +266,7 @@ export const nbTranslations: DefaultTranslationsObject = { nothingFound: 'Ingenting funnet', noValue: 'Ingen verdi', of: 'av', - only: undefined, + only: 'Bare', open: 'Åpne', or: 'Eller', order: 'Rekkefølge', @@ -414,7 +414,7 @@ export const nbTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Sist lagret {{distance}} siden', noFurtherVersionsFound: 'Ingen flere versjoner funnet', noRowsFound: 'Ingen {{label}} funnet', - noRowsSelected: undefined, + noRowsSelected: 'Ingen {{label}} valgt', preview: 'Forhåndsvisning', previouslyPublished: 'Tidligere Publisert', problemRestoringVersion: 'Det oppstod et problem med gjenoppretting av denne versjonen', diff --git a/packages/translations/src/languages/nl.ts b/packages/translations/src/languages/nl.ts index 371bc61e4..8aabe0a9a 100644 --- a/packages/translations/src/languages/nl.ts +++ b/packages/translations/src/languages/nl.ts @@ -188,7 +188,7 @@ export const nlTranslations: DefaultTranslationsObject = { cancel: 'Annuleren', changesNotSaved: 'Uw wijzigingen zijn niet bewaard. Als u weggaat zullen de wijzigingen verloren gaan.', - clearAll: undefined, + clearAll: 'Alles wissen', close: 'Dichtbij', collapse: 'Samenvouwen', collections: 'Collecties', @@ -417,7 +417,7 @@ export const nlTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Laatst opgeslagen {{distance}} geleden', noFurtherVersionsFound: 'Geen verdere versies gevonden', noRowsFound: 'Geen {{label}} gevonden', - noRowsSelected: undefined, + noRowsSelected: 'Geen {{label}} geselecteerd', preview: 'Voorbeeld', previouslyPublished: 'Eerder gepubliceerd', problemRestoringVersion: 'Er was een probleem bij het herstellen van deze versie', diff --git a/packages/translations/src/languages/pl.ts b/packages/translations/src/languages/pl.ts index 2a9491b0f..f8ff36c5f 100644 --- a/packages/translations/src/languages/pl.ts +++ b/packages/translations/src/languages/pl.ts @@ -186,7 +186,7 @@ export const plTranslations: DefaultTranslationsObject = { cancel: 'Anuluj', changesNotSaved: 'Twoje zmiany nie zostały zapisane. Jeśli teraz wyjdziesz, stracisz swoje zmiany.', - clearAll: undefined, + clearAll: 'Wyczyść wszystko', close: 'Zamknij', collapse: 'Zwiń', collections: 'Kolekcje', @@ -414,14 +414,14 @@ export const plTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Ostatnio zapisane {{distance}} temu', noFurtherVersionsFound: 'Nie znaleziono dalszych wersji', noRowsFound: 'Nie znaleziono {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Nie wybrano {{etykieta}}', preview: 'Podgląd', previouslyPublished: 'Wcześniej opublikowane', problemRestoringVersion: 'Wystąpił problem podczas przywracania tej wersji', publish: 'Publikuj', publishChanges: 'Opublikuj zmiany', published: 'Opublikowano', - publishIn: undefined, + publishIn: 'Opublikuj w {{locale}}', publishing: 'Publikacja', restoreAsDraft: 'Przywróć jako szkic', restoredSuccessfully: 'Przywrócono pomyślnie.', diff --git a/packages/translations/src/languages/pt.ts b/packages/translations/src/languages/pt.ts index f8ae147c0..7849984db 100644 --- a/packages/translations/src/languages/pt.ts +++ b/packages/translations/src/languages/pt.ts @@ -187,7 +187,7 @@ export const ptTranslations: DefaultTranslationsObject = { cancel: 'Cancelar', changesNotSaved: 'Suas alterações não foram salvas. Se você sair agora, essas alterações serão perdidas.', - clearAll: undefined, + clearAll: 'Limpar Tudo', close: 'Fechar', collapse: 'Recolher', collections: 'Coleções', @@ -267,7 +267,7 @@ export const ptTranslations: DefaultTranslationsObject = { nothingFound: 'Nada encontrado', noValue: 'Nenhum valor', of: 'de', - only: undefined, + only: 'Apenas', open: 'Abrir', or: 'Ou', order: 'Ordem', @@ -415,14 +415,14 @@ export const ptTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Última gravação há {{distance}}', noFurtherVersionsFound: 'Nenhuma outra versão encontrada', noRowsFound: 'Nenhum(a) {{label}} encontrado(a)', - noRowsSelected: undefined, + noRowsSelected: 'Nenhum {{rótulo}} selecionado', preview: 'Pré-visualização', previouslyPublished: 'Publicado Anteriormente', problemRestoringVersion: 'Ocorreu um problema ao restaurar essa versão', publish: 'Publicar', publishChanges: 'Publicar alterações', published: 'Publicado', - publishIn: undefined, + publishIn: 'Publicar em {{locale}}', publishing: 'Publicação', restoreAsDraft: 'Restaurar como rascunho', restoredSuccessfully: 'Restaurado com sucesso.', diff --git a/packages/translations/src/languages/ro.ts b/packages/translations/src/languages/ro.ts index e2b73f02a..c4d362412 100644 --- a/packages/translations/src/languages/ro.ts +++ b/packages/translations/src/languages/ro.ts @@ -190,7 +190,7 @@ export const roTranslations: DefaultTranslationsObject = { cancel: 'Anulați', changesNotSaved: 'Modificările dvs. nu au fost salvate. Dacă plecați acum, vă veți pierde modificările.', - clearAll: undefined, + clearAll: 'Șterge tot', close: 'Închide', collapse: 'Colaps', collections: 'Colecții', @@ -422,7 +422,7 @@ export const roTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Ultima salvare acum {{distance}}', noFurtherVersionsFound: 'Nu s-au găsit alte versiuni', noRowsFound: 'Nu s-a găsit niciun {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Niciun {{etichetă}} selectat', preview: 'Previzualizare', previouslyPublished: 'Publicat anterior', problemRestoringVersion: 'A existat o problemă la restaurarea acestei versiuni', diff --git a/packages/translations/src/languages/rs.ts b/packages/translations/src/languages/rs.ts index 32e6b1ff6..dcde3aeae 100644 --- a/packages/translations/src/languages/rs.ts +++ b/packages/translations/src/languages/rs.ts @@ -185,7 +185,7 @@ export const rsTranslations: DefaultTranslationsObject = { backToDashboard: 'Назад на контролни панел', cancel: 'Откажи', changesNotSaved: 'Ваше промене нису сачуване. Ако изађете сада, изгубићете промене.', - clearAll: undefined, + clearAll: 'Obriši sve', close: 'Затвори', collapse: 'Скупи', collections: 'Колекције', @@ -265,7 +265,7 @@ export const rsTranslations: DefaultTranslationsObject = { nothingFound: 'Ништа није пронађено', noValue: 'Без вредности', of: 'Од', - only: undefined, + only: 'Samo', open: 'Отвори', or: 'Или', order: 'Редослед', @@ -409,14 +409,14 @@ export const rsTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Задњи пут сачувано пре {{distance}', noFurtherVersionsFound: 'Нису пронађене наредне верзије', noRowsFound: '{{label}} није пронађено', - noRowsSelected: undefined, + noRowsSelected: 'Nije odabrana {{label}}', preview: 'Преглед', previouslyPublished: 'Prethodno objavljeno', problemRestoringVersion: 'Настао је проблем при враћању ове верзије', publish: 'Објавити', publishChanges: 'Објави промене', published: 'Објављено', - publishIn: undefined, + publishIn: 'Objavi na {{locale}}', publishing: 'Objavljivanje', restoreAsDraft: 'Vrati kao nacrt', restoredSuccessfully: 'Успешно враћено.', diff --git a/packages/translations/src/languages/rsLatin.ts b/packages/translations/src/languages/rsLatin.ts index a569053a8..0eeb56736 100644 --- a/packages/translations/src/languages/rsLatin.ts +++ b/packages/translations/src/languages/rsLatin.ts @@ -185,7 +185,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = { backToDashboard: 'Nazad na kontrolni panel', cancel: 'Otkaži', changesNotSaved: 'Vaše promene nisu sačuvane. Ako izađete sada, izgubićete promene.', - clearAll: undefined, + clearAll: 'Očisti sve', close: 'Zatvori', collapse: 'Skupi', collections: 'Kolekcije', @@ -265,7 +265,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = { nothingFound: 'Ništa nije pronađeno', noValue: 'Bez vrednosti', of: 'Od', - only: undefined, + only: 'Samo', open: 'Otvori', or: 'Ili', order: 'Redosled', @@ -410,7 +410,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Zadnji put sačuvano pre {{distance}', noFurtherVersionsFound: 'Nisu pronađene naredne verzije', noRowsFound: '{{label}} nije pronađeno', - noRowsSelected: undefined, + noRowsSelected: 'Nije odabrana {{label}}', preview: 'Pregled', previouslyPublished: 'Prethodno objavljeno', problemRestoringVersion: 'Nastao je problem pri vraćanju ove verzije', diff --git a/packages/translations/src/languages/ru.ts b/packages/translations/src/languages/ru.ts index 176c1514c..c505d0d1a 100644 --- a/packages/translations/src/languages/ru.ts +++ b/packages/translations/src/languages/ru.ts @@ -188,7 +188,7 @@ export const ruTranslations: DefaultTranslationsObject = { cancel: 'Отмена', changesNotSaved: 'Ваши изменения не были сохранены. Если вы сейчас уйдете, то потеряете свои изменения.', - clearAll: undefined, + clearAll: 'Очистить все', close: 'Закрыть', collapse: 'Свернуть', collections: 'Коллекции', @@ -416,7 +416,7 @@ export const ruTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Последний раз сохранено {{distance}} назад', noFurtherVersionsFound: 'Другие версии не найдены', noRowsFound: 'Не найдено {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Не выбран {{label}}', preview: 'Предпросмотр', previouslyPublished: 'Ранее опубликовано', problemRestoringVersion: 'Возникла проблема с восстановлением этой версии', diff --git a/packages/translations/src/languages/sk.ts b/packages/translations/src/languages/sk.ts index 2a6468b9c..95d81cc8f 100644 --- a/packages/translations/src/languages/sk.ts +++ b/packages/translations/src/languages/sk.ts @@ -187,7 +187,7 @@ export const skTranslations: DefaultTranslationsObject = { backToDashboard: 'Späť na nástenku', cancel: 'Zrušiť', changesNotSaved: 'Vaše zmeny neboli uložené. Ak teraz odídete, stratíte svoje zmeny.', - clearAll: undefined, + clearAll: 'Vymazať všetko', close: 'Zavrieť', collapse: 'Zbaliť', collections: 'Kolekcia', @@ -267,7 +267,7 @@ export const skTranslations: DefaultTranslationsObject = { nothingFound: 'Nič nenájdené', noValue: 'Žiadna hodnota', of: 'z', - only: undefined, + only: 'Iba', open: 'Otvoriť', or: 'Alebo', order: 'Poradie', @@ -414,7 +414,7 @@ export const skTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Naposledy uložené pred {{distance}}', noFurtherVersionsFound: 'Nenájdené ďalšie verzie', noRowsFound: 'Nenájdené {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Nie je vybraté žiadne {{označenie}}', preview: 'Náhľad', previouslyPublished: 'Predtým publikované', problemRestoringVersion: 'Pri obnovovaní tejto verzie došlo k problému', diff --git a/packages/translations/src/languages/sv.ts b/packages/translations/src/languages/sv.ts index 038484eef..f57df90f5 100644 --- a/packages/translations/src/languages/sv.ts +++ b/packages/translations/src/languages/sv.ts @@ -186,7 +186,7 @@ export const svTranslations: DefaultTranslationsObject = { cancel: 'Avbryt', changesNotSaved: 'Dina ändringar har inte sparats. Om du lämnar nu kommer du att förlora dina ändringar.', - clearAll: undefined, + clearAll: 'Rensa alla', close: 'Stänga', collapse: 'Kollapsa', collections: 'Samlingar', @@ -413,7 +413,7 @@ export const svTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Senast sparad för {{distance}} sedan', noFurtherVersionsFound: 'Inga fler versioner hittades', noRowsFound: 'Inga {{label}} hittades', - noRowsSelected: undefined, + noRowsSelected: 'Inget {{etikett}} valt', preview: 'Förhandsvisa', previouslyPublished: 'Tidigare publicerad', problemRestoringVersion: 'Det uppstod ett problem när den här versionen skulle återställas', diff --git a/packages/translations/src/languages/th.ts b/packages/translations/src/languages/th.ts index b0ac549e4..f85be73b8 100644 --- a/packages/translations/src/languages/th.ts +++ b/packages/translations/src/languages/th.ts @@ -182,7 +182,7 @@ export const thTranslations: DefaultTranslationsObject = { backToDashboard: 'กลับไปหน้าแดชบอร์ด', cancel: 'ยกเลิก', changesNotSaved: 'การเปลี่ยนแปลงยังไม่ได้ถูกบันทึก ถ้าคุณออกตอนนี้ สิ่งที่แก้ไขไว้จะหายไป', - clearAll: undefined, + clearAll: 'ล้างทั้งหมด', close: 'ปิด', collapse: 'ยุบ', collections: 'Collections', @@ -405,7 +405,7 @@ export const thTranslations: DefaultTranslationsObject = { lastSavedAgo: 'บันทึกครั้งล่าสุด {{distance}} ที่ผ่านมา', noFurtherVersionsFound: 'ไม่พบเวอร์ชันอื่น ๆ', noRowsFound: 'ไม่พบ {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'ไม่มี {{label}} ที่ถูกเลือก', preview: 'ตัวอย่าง', previouslyPublished: 'เผยแพร่ก่อนหน้านี้', problemRestoringVersion: 'เกิดปัญหาระหว่างการกู้คืนเวอร์ชันนี้', diff --git a/packages/translations/src/languages/tr.ts b/packages/translations/src/languages/tr.ts index 35a08fdc9..7fac9e7e8 100644 --- a/packages/translations/src/languages/tr.ts +++ b/packages/translations/src/languages/tr.ts @@ -189,7 +189,7 @@ export const trTranslations: DefaultTranslationsObject = { cancel: 'İptal', changesNotSaved: 'Değişiklikleriniz henüz kaydedilmedi. Eğer bu sayfayı terk ederseniz değişiklikleri kaybedeceksiniz.', - clearAll: undefined, + clearAll: 'Hepsini Temizle', close: 'Kapat', collapse: 'Daralt', collections: 'Koleksiyonlar', @@ -415,7 +415,7 @@ export const trTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Son kaydedildi {{distance}} önce', noFurtherVersionsFound: 'Başka sürüm bulunamadı.', noRowsFound: '{{label}} bulunamadı', - noRowsSelected: undefined, + noRowsSelected: 'Seçilen {{label}} yok', preview: 'Önizleme', previouslyPublished: 'Daha Önce Yayınlanmış', problemRestoringVersion: 'Bu sürüme geri döndürürken bir hatayla karşılaşıldı.', diff --git a/packages/translations/src/languages/uk.ts b/packages/translations/src/languages/uk.ts index 5ef3ec443..3cf4410e0 100644 --- a/packages/translations/src/languages/uk.ts +++ b/packages/translations/src/languages/uk.ts @@ -186,7 +186,7 @@ export const ukTranslations: DefaultTranslationsObject = { backToDashboard: 'Повернутись до головної сторінки', cancel: 'Скасувати', changesNotSaved: 'Ваши зміни не були збережені. Якщо ви вийдете зараз, то втратите свої зміни.', - clearAll: undefined, + clearAll: 'Очистити все', close: 'Закрити', collapse: 'Згорнути', collections: 'Колекції', @@ -413,7 +413,7 @@ export const ukTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Востаннє збережено {{distance}} тому', noFurtherVersionsFound: 'Інших версій не знайдено', noRowsFound: 'Не знайдено {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Не вибрано {{label}}', preview: 'Попередній перегляд', previouslyPublished: 'Раніше опубліковано', problemRestoringVersion: 'Виникла проблема з відновленням цієї версії', diff --git a/packages/translations/src/languages/vi.ts b/packages/translations/src/languages/vi.ts index 4b0f5b4ba..229c1b5f3 100644 --- a/packages/translations/src/languages/vi.ts +++ b/packages/translations/src/languages/vi.ts @@ -184,7 +184,7 @@ export const viTranslations: DefaultTranslationsObject = { backToDashboard: 'Quay lại bảng điều khiển', cancel: 'Hủy', changesNotSaved: 'Thay đổi chưa được lưu lại. Bạn sẽ mất bản chỉnh sửa nếu thoát bây giờ.', - clearAll: undefined, + clearAll: 'Xóa tất cả', close: 'Gần', collapse: 'Thu gọn', collections: 'Collections', @@ -264,7 +264,7 @@ export const viTranslations: DefaultTranslationsObject = { nothingFound: 'Không tìm thấy', noValue: 'Không có giá trị', of: 'trong số', - only: undefined, + only: 'Chỉ', open: 'Mở', or: 'hoặc', order: 'Thứ tự', @@ -408,7 +408,7 @@ export const viTranslations: DefaultTranslationsObject = { lastSavedAgo: 'Lần lưu cuối cùng {{distance}} trước đây', noFurtherVersionsFound: 'Không tìm thấy phiên bản cũ hơn', noRowsFound: 'Không tìm thấy: {{label}}', - noRowsSelected: undefined, + noRowsSelected: 'Không có {{label}} được chọn', preview: 'Bản xem trước', previouslyPublished: 'Đã xuất bản trước đây', problemRestoringVersion: 'Đã xảy ra vấn đề khi khôi phục phiên bản này', diff --git a/packages/translations/src/languages/zh.ts b/packages/translations/src/languages/zh.ts index 00082a3cf..32d76d7d9 100644 --- a/packages/translations/src/languages/zh.ts +++ b/packages/translations/src/languages/zh.ts @@ -179,7 +179,7 @@ export const zhTranslations: DefaultTranslationsObject = { backToDashboard: '返回到仪表板', cancel: '取消', changesNotSaved: '您的更改尚未保存。您确定要离开吗?', - clearAll: undefined, + clearAll: '清除全部', close: '关闭', collapse: '折叠', collections: '集合', @@ -258,7 +258,7 @@ export const zhTranslations: DefaultTranslationsObject = { nothingFound: '没有找到任何东西', noValue: '没有值', of: '的', - only: undefined, + only: '仅', open: '打开', or: '或', order: '排序', @@ -398,14 +398,14 @@ export const zhTranslations: DefaultTranslationsObject = { lastSavedAgo: '上次保存{{distance}}之前', noFurtherVersionsFound: '没有发现其他版本', noRowsFound: '没有发现{{label}}', - noRowsSelected: undefined, + noRowsSelected: '未选择{{label}}', preview: '预览', previouslyPublished: '先前发布过的', problemRestoringVersion: '恢复这个版本时发生了问题', publish: '发布', publishChanges: '发布修改', published: '已发布', - publishIn: undefined, + publishIn: '在{{locale}}发布', publishing: '发布', restoreAsDraft: '恢复为草稿', restoredSuccessfully: '恢复成功。', diff --git a/packages/translations/src/languages/zhTw.ts b/packages/translations/src/languages/zhTw.ts index 0bc3985b4..bdace266a 100644 --- a/packages/translations/src/languages/zhTw.ts +++ b/packages/translations/src/languages/zhTw.ts @@ -179,7 +179,7 @@ export const zhTwTranslations: DefaultTranslationsObject = { backToDashboard: '返回到控制面板', cancel: '取消', changesNotSaved: '您還有尚未儲存的變更。您確定要離開嗎?', - clearAll: undefined, + clearAll: '清除全部', close: '關閉', collapse: '折疊', collections: '集合', @@ -398,14 +398,14 @@ export const zhTwTranslations: DefaultTranslationsObject = { lastSavedAgo: '上次儲存在{{distance}}之前', noFurtherVersionsFound: '沒有發現其他版本', noRowsFound: '沒有發現{{label}}', - noRowsSelected: undefined, + noRowsSelected: '未選擇 {{label}}', preview: '預覽', previouslyPublished: '先前出版過的', problemRestoringVersion: '回復這個版本時發生了問題', publish: '發佈', publishChanges: '發佈修改', published: '已發佈', - publishIn: undefined, + publishIn: '在 {{locale}} 發佈', publishing: '發布', restoreAsDraft: '恢復為草稿', restoredSuccessfully: '回復成功。', diff --git a/packages/ui/src/providers/Auth/index.tsx b/packages/ui/src/providers/Auth/index.tsx index 8b82623c9..fa5b90290 100644 --- a/packages/ui/src/providers/Auth/index.tsx +++ b/packages/ui/src/providers/Auth/index.tsx @@ -1,5 +1,5 @@ 'use client' -import type { ClientUser, MeOperationResult, Permissions } from 'payload' +import type { ClientUser, MeOperationResult, Permissions, User } from 'payload' import { useModal } from '@faceless-ui/modal' import { usePathname, useRouter } from 'next/navigation.js' @@ -15,7 +15,7 @@ import { formatAdminURL } from '../../utilities/formatAdminURL.js' import { useConfig } from '../Config/index.js' export type AuthContext = { - fetchFullUser: () => Promise + fetchFullUser: () => Promise logOut: () => Promise permissions?: Permissions refreshCookie: (forceRefresh?: boolean) => void @@ -227,6 +227,7 @@ export function AuthProvider({ const fetchFullUser = React.useCallback(async () => { try { const request = await requests.get(`${serverURL}${apiRoute}/${userSlug}/me`, { + credentials: 'include', headers: { 'Accept-Language': i18n.language, }, @@ -234,9 +235,11 @@ export function AuthProvider({ if (request.status === 200) { const json: MeOperationResult = await request.json() + let user = null if (json?.user) { setUser(json.user) + user = json.user if (json?.token) { setTokenAndExpiration(json) @@ -245,10 +248,14 @@ export function AuthProvider({ setUser(null) revokeTokenAndExpire() } + + return user } } catch (e) { toast.error(`Fetching user failed: ${e.message}`) } + + return null }, [serverURL, apiRoute, userSlug, i18n.language, setTokenAndExpiration, revokeTokenAndExpire]) // On mount, get user and set diff --git a/test/access-control/e2e.spec.ts b/test/access-control/e2e.spec.ts index ea9857e2f..984d7baee 100644 --- a/test/access-control/e2e.spec.ts +++ b/test/access-control/e2e.spec.ts @@ -482,7 +482,7 @@ describe('access control', () => { serverURL, }) - await expect(page.locator('.next-error-h1')).toBeVisible() + await expect(page.locator('.unauthorized')).toBeVisible() await page.goto(logoutURL) await page.waitForURL(logoutURL) @@ -500,6 +500,7 @@ describe('access control', () => { test('should block admin access to non-admin user', async () => { const adminURL = `${serverURL}/admin` + const unauthorizedURL = `${serverURL}/admin/unauthorized` await page.goto(adminURL) await page.waitForURL(adminURL) @@ -527,9 +528,9 @@ describe('access control', () => { ]) await page.goto(adminURL) - await page.waitForURL(adminURL) + await page.waitForURL(unauthorizedURL) - await expect(page.locator('.next-error-h1')).toBeVisible() + await expect(page.locator('.unauthorized')).toBeVisible() }) }) diff --git a/test/helpers.ts b/test/helpers.ts index ba71c8681..66ad582d4 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -310,6 +310,7 @@ export function initPageConsoleErrorCatch(page: Page) { !msg.text().includes('the server responded with a status of') && !msg.text().includes('Failed to fetch RSC payload for') && !msg.text().includes('Error: NEXT_NOT_FOUND') && + !msg.text().includes('Error: NEXT_REDIRECT') && !msg.text().includes('Error getting document data') ) { // "Failed to fetch RSC payload for" happens seemingly randomly. There are lots of issues in the next.js repository for this. Causes e2e tests to fail and flake. Will ignore for now