fix: verify view is inaccessible (#8557)
Fixes https://github.com/payloadcms/payload/issues/8470 Cleans up the way we redirect and where it happens. ## Improvements - When you verify, the admin panel will display a toast when it redirects you to the login route. This is contextually helpful as to what is happening. - Removes dead code path, as we always set the _verifiedToken to null after it is used. ## `handleAdminPage` renamed to `getRouteInfo` This function no longer handles routing. It kicks that responsibility back up to the initPage function. ## `isAdminAuthRoute` renamed to `isPublicAdminRoute` This was inversely named as it determines if a given route is public. Also simplifies deterministic logic here. ## `redirectUnauthenticatedUser` argument This is no longer used or needed. We can determine these things by using the `isPublicAdminRoute` function. ## View Style fixes - Reset Password - Forgot Password - Unauthorized
This commit is contained in:
@@ -19,8 +19,8 @@ export function login(collection: Collection): any {
|
|||||||
|
|
||||||
const result = await loginOperation(options)
|
const result = await loginOperation(options)
|
||||||
const cookie = generatePayloadCookie({
|
const cookie = generatePayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: context.req.payload,
|
cookiePrefix: context.req.payload.config.cookiePrefix,
|
||||||
token: result.token,
|
token: result.token,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ export function logout(collection: Collection): any {
|
|||||||
|
|
||||||
const result = await logoutOperation(options)
|
const result = await logoutOperation(options)
|
||||||
const expiredCookie = generateExpiredPayloadCookie({
|
const expiredCookie = generateExpiredPayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: context.req.payload,
|
config: context.req.payload.config,
|
||||||
|
cookiePrefix: context.req.payload.config.cookiePrefix,
|
||||||
})
|
})
|
||||||
context.headers['Set-Cookie'] = expiredCookie
|
context.headers['Set-Cookie'] = expiredCookie
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ export function refresh(collection: Collection): any {
|
|||||||
|
|
||||||
const result = await refreshOperation(options)
|
const result = await refreshOperation(options)
|
||||||
const cookie = generatePayloadCookie({
|
const cookie = generatePayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: context.req.payload,
|
cookiePrefix: context.req.payload.config.cookiePrefix,
|
||||||
token: result.refreshedToken,
|
token: result.refreshedToken,
|
||||||
})
|
})
|
||||||
context.headers['Set-Cookie'] = cookie
|
context.headers['Set-Cookie'] = cookie
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ export function resetPassword(collection: Collection): any {
|
|||||||
|
|
||||||
const result = await resetPasswordOperation(options)
|
const result = await resetPasswordOperation(options)
|
||||||
const cookie = generatePayloadCookie({
|
const cookie = generatePayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: context.req.payload,
|
cookiePrefix: context.req.payload.config.cookiePrefix,
|
||||||
token: result.token,
|
token: result.token,
|
||||||
})
|
})
|
||||||
context.headers['Set-Cookie'] = cookie
|
context.headers['Set-Cookie'] = cookie
|
||||||
|
|||||||
6
packages/next/src/elements/FormHeader/index.scss
Normal file
6
packages/next/src/elements/FormHeader/index.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.form-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: calc(var(--base) * .5);
|
||||||
|
margin-bottom: var(--base);
|
||||||
|
}
|
||||||
22
packages/next/src/elements/FormHeader/index.tsx
Normal file
22
packages/next/src/elements/FormHeader/index.tsx
Normal file
@@ -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 (
|
||||||
|
<div className={baseClass}>
|
||||||
|
<h1>{heading}</h1>
|
||||||
|
{Boolean(description) && <p>{description}</p>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -29,8 +29,8 @@ export const login: CollectionRouteHandler = async ({ collection, req }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const cookie = generatePayloadCookie({
|
const cookie = generatePayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: req.payload,
|
cookiePrefix: req.payload.config.cookiePrefix,
|
||||||
token: result.token,
|
token: result.token,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,9 @@ export const logout: CollectionRouteHandler = async ({ collection, req }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const expiredCookie = generateExpiredPayloadCookie({
|
const expiredCookie = generateExpiredPayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: req.payload,
|
config: req.payload.config,
|
||||||
|
cookiePrefix: req.payload.config.cookiePrefix,
|
||||||
})
|
})
|
||||||
|
|
||||||
headers.set('Set-Cookie', expiredCookie)
|
headers.set('Set-Cookie', expiredCookie)
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ export const refresh: CollectionRouteHandler = async ({ collection, req }) => {
|
|||||||
|
|
||||||
if (result.setCookie) {
|
if (result.setCookie) {
|
||||||
const cookie = generatePayloadCookie({
|
const cookie = generatePayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: req.payload,
|
cookiePrefix: req.payload.config.cookiePrefix,
|
||||||
token: result.refreshedToken,
|
token: result.refreshedToken,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ export const registerFirstUser: CollectionRouteHandler = async ({ collection, re
|
|||||||
})
|
})
|
||||||
|
|
||||||
const cookie = generatePayloadCookie({
|
const cookie = generatePayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: req.payload,
|
cookiePrefix: req.payload.config.cookiePrefix,
|
||||||
token: result.token,
|
token: result.token,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ export const resetPassword: CollectionRouteHandler = async ({ collection, req })
|
|||||||
})
|
})
|
||||||
|
|
||||||
const cookie = generatePayloadCookie({
|
const cookie = generatePayloadCookie({
|
||||||
collectionConfig: collection.config,
|
collectionAuthConfig: collection.config.auth,
|
||||||
payload: req.payload,
|
cookiePrefix: req.payload.config.cookiePrefix,
|
||||||
token: result.token,
|
token: result.token,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,21 @@
|
|||||||
import type {
|
import type { SanitizedCollectionConfig, SanitizedConfig, SanitizedGlobalConfig } from 'payload'
|
||||||
Permissions,
|
|
||||||
SanitizedCollectionConfig,
|
|
||||||
SanitizedConfig,
|
|
||||||
SanitizedGlobalConfig,
|
|
||||||
} from 'payload'
|
|
||||||
|
|
||||||
import { notFound } from 'next/navigation.js'
|
import { getRouteWithoutAdmin, isAdminRoute } from './shared.js'
|
||||||
|
|
||||||
import { getRouteWithoutAdmin, isAdminAuthRoute, isAdminRoute } from './shared.js'
|
type Args = {
|
||||||
|
|
||||||
export const handleAdminPage = ({
|
|
||||||
adminRoute,
|
|
||||||
config,
|
|
||||||
permissions,
|
|
||||||
route,
|
|
||||||
}: {
|
|
||||||
adminRoute: string
|
adminRoute: string
|
||||||
config: SanitizedConfig
|
config: SanitizedConfig
|
||||||
permissions: Permissions
|
|
||||||
route: string
|
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 })) {
|
if (isAdminRoute({ adminRoute, config, route })) {
|
||||||
const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route })
|
const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route })
|
||||||
const routeSegments = routeWithoutAdmin.split('/').filter(Boolean)
|
const routeSegments = routeWithoutAdmin.split('/').filter(Boolean)
|
||||||
@@ -33,28 +29,18 @@ export const handleAdminPage = ({
|
|||||||
|
|
||||||
if (collectionSlug) {
|
if (collectionSlug) {
|
||||||
collectionConfig = config.collections.find((collection) => collection.slug === collectionSlug)
|
collectionConfig = config.collections.find((collection) => collection.slug === collectionSlug)
|
||||||
|
|
||||||
if (!collectionConfig) {
|
|
||||||
notFound()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalSlug) {
|
if (globalSlug) {
|
||||||
globalConfig = config.globals.find((global) => global.slug === globalSlug)
|
globalConfig = config.globals.find((global) => global.slug === globalSlug)
|
||||||
|
|
||||||
if (!globalConfig) {
|
|
||||||
notFound()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!permissions.canAccessAdmin && !isAdminAuthRoute({ adminRoute, config, route })) {
|
|
||||||
notFound()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
collectionConfig,
|
collectionConfig,
|
||||||
|
collectionSlug,
|
||||||
docID,
|
docID,
|
||||||
globalConfig,
|
globalConfig,
|
||||||
|
globalSlug,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +1,46 @@
|
|||||||
|
import type { User } from 'payload'
|
||||||
|
|
||||||
import { formatAdminURL } from '@payloadcms/ui/shared'
|
import { formatAdminURL } from '@payloadcms/ui/shared'
|
||||||
import { redirect } from 'next/navigation.js'
|
|
||||||
import * as qs from 'qs-esm'
|
import * as qs from 'qs-esm'
|
||||||
|
|
||||||
import { isAdminAuthRoute, isAdminRoute } from './shared.js'
|
type Args = {
|
||||||
|
|
||||||
export const handleAuthRedirect = ({
|
|
||||||
config,
|
|
||||||
redirectUnauthenticatedUser,
|
|
||||||
route,
|
|
||||||
searchParams,
|
|
||||||
}: {
|
|
||||||
config
|
config
|
||||||
redirectUnauthenticatedUser: boolean | string
|
|
||||||
route: string
|
route: string
|
||||||
searchParams: { [key: string]: string | string[] }
|
searchParams: { [key: string]: string | string[] }
|
||||||
}) => {
|
user?: User
|
||||||
|
}
|
||||||
|
export const handleAuthRedirect = ({ config, route, searchParams, user }: Args): string => {
|
||||||
const {
|
const {
|
||||||
admin: {
|
admin: {
|
||||||
routes: { login: loginRouteFromConfig },
|
routes: { login: loginRouteFromConfig, unauthorized: unauthorizedRoute },
|
||||||
},
|
},
|
||||||
routes: { admin: adminRoute },
|
routes: { admin: adminRoute },
|
||||||
} = config
|
} = config
|
||||||
|
|
||||||
if (!isAdminAuthRoute({ adminRoute, config, route })) {
|
if (searchParams && 'redirect' in searchParams) {
|
||||||
if (searchParams && 'redirect' in searchParams) {
|
delete searchParams.redirect
|
||||||
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}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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}`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { InitPageResult, Locale, PayloadRequest, VisibleEntities } from 'pa
|
|||||||
|
|
||||||
import { findLocaleFromCode } from '@payloadcms/ui/shared'
|
import { findLocaleFromCode } from '@payloadcms/ui/shared'
|
||||||
import { headers as getHeaders } from 'next/headers.js'
|
import { headers as getHeaders } from 'next/headers.js'
|
||||||
|
import { notFound } from 'next/navigation.js'
|
||||||
import { createLocalReq, isEntityHidden, parseCookies } from 'payload'
|
import { createLocalReq, isEntityHidden, parseCookies } from 'payload'
|
||||||
import * as qs from 'qs-esm'
|
import * as qs from 'qs-esm'
|
||||||
|
|
||||||
@@ -9,13 +10,13 @@ import type { Args } from './types.js'
|
|||||||
|
|
||||||
import { getPayloadHMR } from '../getPayloadHMR.js'
|
import { getPayloadHMR } from '../getPayloadHMR.js'
|
||||||
import { initReq } from '../initReq.js'
|
import { initReq } from '../initReq.js'
|
||||||
import { handleAdminPage } from './handleAdminPage.js'
|
import { getRouteInfo } from './handleAdminPage.js'
|
||||||
import { handleAuthRedirect } from './handleAuthRedirect.js'
|
import { handleAuthRedirect } from './handleAuthRedirect.js'
|
||||||
|
import { isPublicAdminRoute } from './shared.js'
|
||||||
|
|
||||||
export const initPage = async ({
|
export const initPage = async ({
|
||||||
config: configPromise,
|
config: configPromise,
|
||||||
importMap,
|
importMap,
|
||||||
redirectUnauthenticatedUser = false,
|
|
||||||
route,
|
route,
|
||||||
searchParams,
|
searchParams,
|
||||||
}: Args): Promise<InitPageResult> => {
|
}: Args): Promise<InitPageResult> => {
|
||||||
@@ -128,22 +129,30 @@ export const initPage = async ({
|
|||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redirectUnauthenticatedUser && !user) {
|
let redirectTo = null
|
||||||
handleAuthRedirect({
|
|
||||||
|
if (
|
||||||
|
!permissions.canAccessAdmin &&
|
||||||
|
!isPublicAdminRoute({ adminRoute, config: payload.config, route })
|
||||||
|
) {
|
||||||
|
redirectTo = handleAuthRedirect({
|
||||||
config: payload.config,
|
config: payload.config,
|
||||||
redirectUnauthenticatedUser,
|
|
||||||
route,
|
route,
|
||||||
searchParams,
|
searchParams,
|
||||||
|
user,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const { collectionConfig, docID, globalConfig } = handleAdminPage({
|
const { collectionConfig, collectionSlug, docID, globalConfig, globalSlug } = getRouteInfo({
|
||||||
adminRoute,
|
adminRoute,
|
||||||
config: payload.config,
|
config: payload.config,
|
||||||
permissions,
|
|
||||||
route,
|
route,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if ((collectionSlug && !collectionConfig) || (globalSlug && !globalConfig)) {
|
||||||
|
return notFound()
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
collectionConfig,
|
collectionConfig,
|
||||||
cookies,
|
cookies,
|
||||||
@@ -152,6 +161,7 @@ export const initPage = async ({
|
|||||||
languageOptions,
|
languageOptions,
|
||||||
locale,
|
locale,
|
||||||
permissions,
|
permissions,
|
||||||
|
redirectTo,
|
||||||
req,
|
req,
|
||||||
translations: i18n.translations,
|
translations: i18n.translations,
|
||||||
visibleEntities,
|
visibleEntities,
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import type { SanitizedConfig } from 'payload'
|
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',
|
'createFirstUser',
|
||||||
'forgot',
|
'forgot',
|
||||||
'login',
|
'login',
|
||||||
@@ -13,17 +17,16 @@ const authRouteKeys: (keyof SanitizedConfig['admin']['routes'])[] = [
|
|||||||
|
|
||||||
export const isAdminRoute = ({
|
export const isAdminRoute = ({
|
||||||
adminRoute,
|
adminRoute,
|
||||||
config,
|
|
||||||
route,
|
route,
|
||||||
}: {
|
}: {
|
||||||
adminRoute: string
|
adminRoute: string
|
||||||
config: SanitizedConfig
|
config: SanitizedConfig
|
||||||
route: string
|
route: string
|
||||||
}): boolean => {
|
}): boolean => {
|
||||||
return route.startsWith(adminRoute) && !isAdminAuthRoute({ adminRoute, config, route })
|
return route.startsWith(adminRoute)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isAdminAuthRoute = ({
|
export const isPublicAdminRoute = ({
|
||||||
adminRoute,
|
adminRoute,
|
||||||
config,
|
config,
|
||||||
route,
|
route,
|
||||||
@@ -32,13 +35,17 @@ export const isAdminAuthRoute = ({
|
|||||||
config: SanitizedConfig
|
config: SanitizedConfig
|
||||||
route: string
|
route: string
|
||||||
}): boolean => {
|
}): boolean => {
|
||||||
const authRoutes = config.admin?.routes
|
return publicAdminRoutes.some((routeSegment) => {
|
||||||
? Object.entries(config.admin.routes)
|
const segment = config.admin?.routes?.[routeSegment] || routeSegment
|
||||||
.filter(([key]) => authRouteKeys.includes(key as keyof SanitizedConfig['admin']['routes']))
|
const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route })
|
||||||
.map(([_, value]) => value)
|
if (routeWithoutAdmin.startsWith(segment)) {
|
||||||
: []
|
return true
|
||||||
|
} else if (routeWithoutAdmin.includes('/verify/')) {
|
||||||
return authRoutes.some((r) => getRouteWithoutAdmin({ adminRoute, route }).startsWith(r))
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getRouteWithoutAdmin = ({
|
export const getRouteWithoutAdmin = ({
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import type { FormState, PayloadRequest } from 'payload'
|
|||||||
|
|
||||||
import { EmailField, Form, FormSubmit, TextField, useConfig, useTranslation } from '@payloadcms/ui'
|
import { EmailField, Form, FormSubmit, TextField, useConfig, useTranslation } from '@payloadcms/ui'
|
||||||
import { email, text } from 'payload/shared'
|
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 = () => {
|
export const ForgotPasswordForm: React.FC = () => {
|
||||||
const { config } = useConfig()
|
const { config } = useConfig()
|
||||||
@@ -54,10 +56,10 @@ export const ForgotPasswordForm: React.FC = () => {
|
|||||||
|
|
||||||
if (hasSubmitted) {
|
if (hasSubmitted) {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<FormHeader
|
||||||
<h1>{t('authentication:emailSent')}</h1>
|
description={t('authentication:checkYourEmailForPasswordReset')}
|
||||||
<p>{t('authentication:checkYourEmailForPasswordReset')}</p>
|
heading={t('authentication:emailSent')}
|
||||||
</Fragment>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +70,14 @@ export const ForgotPasswordForm: React.FC = () => {
|
|||||||
initialState={initialState}
|
initialState={initialState}
|
||||||
method="POST"
|
method="POST"
|
||||||
>
|
>
|
||||||
<h1>{t('authentication:forgotPassword')}</h1>
|
<FormHeader
|
||||||
<p>
|
description={
|
||||||
{loginWithUsername
|
loginWithUsername
|
||||||
? t('authentication:forgotPasswordUsernameInstructions')
|
? t('authentication:forgotPasswordUsernameInstructions')
|
||||||
: t('authentication:forgotPasswordEmailInstructions')}
|
: t('authentication:forgotPasswordEmailInstructions')
|
||||||
</p>
|
}
|
||||||
|
heading={t('authentication:forgotPassword')}
|
||||||
|
/>
|
||||||
|
|
||||||
{loginWithUsername ? (
|
{loginWithUsername ? (
|
||||||
<TextField
|
<TextField
|
||||||
@@ -120,7 +124,7 @@ export const ForgotPasswordForm: React.FC = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<FormSubmit>{t('general:submit')}</FormSubmit>
|
<FormSubmit size="large">{t('general:submit')}</FormSubmit>
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { formatAdminURL, Translation } from '@payloadcms/ui/shared'
|
|||||||
import LinkImport from 'next/link.js'
|
import LinkImport from 'next/link.js'
|
||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
|
|
||||||
|
import { FormHeader } from '../../elements/FormHeader/index.js'
|
||||||
import { ForgotPasswordForm } from './ForgotPasswordForm/index.js'
|
import { ForgotPasswordForm } from './ForgotPasswordForm/index.js'
|
||||||
|
|
||||||
export { generateForgotPasswordMetadata } from './meta.js'
|
export { generateForgotPasswordMetadata } from './meta.js'
|
||||||
@@ -31,26 +32,27 @@ export const ForgotPasswordView: React.FC<AdminViewProps> = ({ initPageResult })
|
|||||||
if (user) {
|
if (user) {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<h1>{i18n.t('authentication:alreadyLoggedIn')}</h1>
|
<FormHeader
|
||||||
<p>
|
description={
|
||||||
<Translation
|
<Translation
|
||||||
elements={{
|
elements={{
|
||||||
'0': ({ children }) => (
|
'0': ({ children }) => (
|
||||||
<Link
|
<Link
|
||||||
href={formatAdminURL({
|
href={formatAdminURL({
|
||||||
adminRoute,
|
adminRoute,
|
||||||
path: accountRoute,
|
path: accountRoute,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
i18nKey="authentication:loggedInChangePassword"
|
i18nKey="authentication:loggedInChangePassword"
|
||||||
t={i18n.t}
|
t={i18n.t}
|
||||||
/>
|
/>
|
||||||
</p>
|
}
|
||||||
<br />
|
heading={i18n.t('authentication:alreadyLoggedIn')}
|
||||||
|
/>
|
||||||
<Button buttonStyle="secondary" el="link" Link={Link} size="large" to={adminRoute}>
|
<Button buttonStyle="secondary" el="link" Link={Link} size="large" to={adminRoute}>
|
||||||
{i18n.t('general:backToDashboard')}
|
{i18n.t('general:backToDashboard')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FormState } from 'payload'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ConfirmPasswordField,
|
ConfirmPasswordField,
|
||||||
Form,
|
Form,
|
||||||
@@ -13,8 +11,8 @@ import {
|
|||||||
} from '@payloadcms/ui'
|
} from '@payloadcms/ui'
|
||||||
import { formatAdminURL } from '@payloadcms/ui/shared'
|
import { formatAdminURL } from '@payloadcms/ui/shared'
|
||||||
import { useRouter } from 'next/navigation.js'
|
import { useRouter } from 'next/navigation.js'
|
||||||
|
import { type FormState } from 'payload'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { toast } from 'sonner'
|
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
readonly token: string
|
readonly token: string
|
||||||
@@ -33,7 +31,7 @@ const initialState: FormState = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ResetPasswordClient: React.FC<Args> = ({ token }) => {
|
export const ResetPasswordForm: React.FC<Args> = ({ token }) => {
|
||||||
const i18n = useTranslation()
|
const i18n = useTranslation()
|
||||||
const {
|
const {
|
||||||
config: {
|
config: {
|
||||||
@@ -47,26 +45,21 @@ export const ResetPasswordClient: React.FC<Args> = ({ token }) => {
|
|||||||
} = useConfig()
|
} = useConfig()
|
||||||
|
|
||||||
const history = useRouter()
|
const history = useRouter()
|
||||||
|
|
||||||
const { fetchFullUser } = useAuth()
|
const { fetchFullUser } = useAuth()
|
||||||
|
|
||||||
const onSuccess = React.useCallback(
|
const onSuccess = React.useCallback(async () => {
|
||||||
async (data) => {
|
const user = await fetchFullUser()
|
||||||
if (data.token) {
|
if (user) {
|
||||||
await fetchFullUser()
|
history.push(adminRoute)
|
||||||
history.push(adminRoute)
|
} else {
|
||||||
} else {
|
history.push(
|
||||||
history.push(
|
formatAdminURL({
|
||||||
formatAdminURL({
|
adminRoute,
|
||||||
adminRoute,
|
path: loginRoute,
|
||||||
path: loginRoute,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
}
|
||||||
toast.success(i18n.t('general:updatedSuccessfully'))
|
}, [adminRoute, fetchFullUser, history, loginRoute])
|
||||||
}
|
|
||||||
},
|
|
||||||
[adminRoute, fetchFullUser, history, i18n, loginRoute],
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
@@ -75,7 +68,7 @@ export const ResetPasswordClient: React.FC<Args> = ({ token }) => {
|
|||||||
method="POST"
|
method="POST"
|
||||||
onSuccess={onSuccess}
|
onSuccess={onSuccess}
|
||||||
>
|
>
|
||||||
<div className={'inputWrap'}>
|
<div className="inputWrap">
|
||||||
<PasswordField
|
<PasswordField
|
||||||
field={{
|
field={{
|
||||||
name: 'password',
|
name: 'password',
|
||||||
@@ -1,33 +1,11 @@
|
|||||||
@import '../../scss/styles.scss';
|
@import '../../scss/styles.scss';
|
||||||
|
|
||||||
@layer payload-default {
|
@layer payload-default {
|
||||||
.reset-password {
|
.reset-password__wrap {
|
||||||
&__wrap {
|
.inputWrap {
|
||||||
z-index: 1;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
|
||||||
gap: base(0.8);
|
gap: base(0.8);
|
||||||
max-width: base(36);
|
|
||||||
|
|
||||||
& > form {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& > .inputWrap {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: base(0.8);
|
|
||||||
|
|
||||||
> * {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .btn {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import { formatAdminURL, Translation } from '@payloadcms/ui/shared'
|
|||||||
import LinkImport from 'next/link.js'
|
import LinkImport from 'next/link.js'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { ResetPasswordClient } from './index.client.js'
|
import { FormHeader } from '../../elements/FormHeader/index.js'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
import { ResetPasswordForm } from './ResetPasswordForm/index.js'
|
||||||
|
|
||||||
export const resetPasswordBaseClass = 'reset-password'
|
export const resetPasswordBaseClass = 'reset-password'
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
admin: {
|
admin: {
|
||||||
routes: { account: accountRoute },
|
routes: { account: accountRoute, login: loginRoute },
|
||||||
},
|
},
|
||||||
routes: { admin: adminRoute },
|
routes: { admin: adminRoute },
|
||||||
} = config
|
} = config
|
||||||
@@ -37,25 +38,27 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
|
|||||||
if (user) {
|
if (user) {
|
||||||
return (
|
return (
|
||||||
<div className={`${resetPasswordBaseClass}__wrap`}>
|
<div className={`${resetPasswordBaseClass}__wrap`}>
|
||||||
<h1>{i18n.t('authentication:alreadyLoggedIn')}</h1>
|
<FormHeader
|
||||||
<p>
|
description={
|
||||||
<Translation
|
<Translation
|
||||||
elements={{
|
elements={{
|
||||||
'0': ({ children }) => (
|
'0': ({ children }) => (
|
||||||
<Link
|
<Link
|
||||||
href={formatAdminURL({
|
href={formatAdminURL({
|
||||||
adminRoute,
|
adminRoute,
|
||||||
path: accountRoute,
|
path: accountRoute,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
i18nKey="authentication:loggedInChangePassword"
|
i18nKey="authentication:loggedInChangePassword"
|
||||||
t={i18n.t}
|
t={i18n.t}
|
||||||
/>
|
/>
|
||||||
</p>
|
}
|
||||||
|
heading={i18n.t('authentication:alreadyLoggedIn')}
|
||||||
|
/>
|
||||||
<Button buttonStyle="secondary" el="link" Link={Link} size="large" to={adminRoute}>
|
<Button buttonStyle="secondary" el="link" Link={Link} size="large" to={adminRoute}>
|
||||||
{i18n.t('general:backToDashboard')}
|
{i18n.t('general:backToDashboard')}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -65,8 +68,16 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${resetPasswordBaseClass}__wrap`}>
|
<div className={`${resetPasswordBaseClass}__wrap`}>
|
||||||
<h1>{i18n.t('authentication:resetPassword')}</h1>
|
<FormHeader heading={i18n.t('authentication:resetPassword')} />
|
||||||
<ResetPasswordClient token={token} />
|
<ResetPasswordForm token={token} />
|
||||||
|
<Link
|
||||||
|
href={formatAdminURL({
|
||||||
|
adminRoute,
|
||||||
|
path: loginRoute,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{i18n.t('authentication:backToLogin')}
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ export const getViewFromConfig = ({
|
|||||||
}
|
}
|
||||||
templateClassName = 'dashboard'
|
templateClassName = 'dashboard'
|
||||||
templateType = 'default'
|
templateType = 'default'
|
||||||
initPageOptions.redirectUnauthenticatedUser = true
|
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -132,7 +131,6 @@ export const getViewFromConfig = ({
|
|||||||
templateType = 'minimal'
|
templateType = 'minimal'
|
||||||
|
|
||||||
if (viewKey === 'account') {
|
if (viewKey === 'account') {
|
||||||
initPageOptions.redirectUnauthenticatedUser = true
|
|
||||||
templateType = 'default'
|
templateType = 'default'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,7 +148,6 @@ export const getViewFromConfig = ({
|
|||||||
|
|
||||||
if (isCollection) {
|
if (isCollection) {
|
||||||
// --> /collections/:collectionSlug
|
// --> /collections/:collectionSlug
|
||||||
initPageOptions.redirectUnauthenticatedUser = true
|
|
||||||
|
|
||||||
ViewToRender = {
|
ViewToRender = {
|
||||||
Component: ListView,
|
Component: ListView,
|
||||||
@@ -160,7 +157,6 @@ export const getViewFromConfig = ({
|
|||||||
templateType = 'default'
|
templateType = 'default'
|
||||||
} else if (isGlobal) {
|
} else if (isGlobal) {
|
||||||
// --> /globals/:globalSlug
|
// --> /globals/:globalSlug
|
||||||
initPageOptions.redirectUnauthenticatedUser = true
|
|
||||||
|
|
||||||
ViewToRender = {
|
ViewToRender = {
|
||||||
Component: DocumentView,
|
Component: DocumentView,
|
||||||
@@ -187,7 +183,6 @@ export const getViewFromConfig = ({
|
|||||||
// --> /collections/:collectionSlug/:id/versions
|
// --> /collections/:collectionSlug/:id/versions
|
||||||
// --> /collections/:collectionSlug/:id/versions/:versionId
|
// --> /collections/:collectionSlug/:id/versions/:versionId
|
||||||
// --> /collections/:collectionSlug/:id/api
|
// --> /collections/:collectionSlug/:id/api
|
||||||
initPageOptions.redirectUnauthenticatedUser = true
|
|
||||||
|
|
||||||
ViewToRender = {
|
ViewToRender = {
|
||||||
Component: DocumentView,
|
Component: DocumentView,
|
||||||
@@ -201,7 +196,6 @@ export const getViewFromConfig = ({
|
|||||||
// --> /globals/:globalSlug/preview
|
// --> /globals/:globalSlug/preview
|
||||||
// --> /globals/:globalSlug/versions/:versionId
|
// --> /globals/:globalSlug/versions/:versionId
|
||||||
// --> /globals/:globalSlug/api
|
// --> /globals/:globalSlug/api
|
||||||
initPageOptions.redirectUnauthenticatedUser = true
|
|
||||||
|
|
||||||
ViewToRender = {
|
ViewToRender = {
|
||||||
Component: DocumentView,
|
Component: DocumentView,
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ export const RootPage = async ({
|
|||||||
|
|
||||||
const initPageResult = await initPage(initPageOptions)
|
const initPageResult = await initPage(initPageOptions)
|
||||||
|
|
||||||
|
if (typeof initPageResult?.redirectTo === 'string') {
|
||||||
|
redirect(initPageResult.redirectTo)
|
||||||
|
}
|
||||||
|
|
||||||
if (initPageResult) {
|
if (initPageResult) {
|
||||||
dbHasUser = await initPageResult?.req.payload.db
|
dbHasUser = await initPageResult?.req.payload.db
|
||||||
.findOne({
|
.findOne({
|
||||||
@@ -137,8 +141,8 @@ export const RootPage = async ({
|
|||||||
visibleEntities={{
|
visibleEntities={{
|
||||||
// The reason we are not passing in initPageResult.visibleEntities directly is due to a "Cannot assign to read only property of object '#<Object>" error introduced in React 19
|
// The reason we are not passing in initPageResult.visibleEntities directly is due to a "Cannot assign to read only property of object '#<Object>" error introduced in React 19
|
||||||
// which this caused as soon as initPageResult.visibleEntities is passed in
|
// which this caused as soon as initPageResult.visibleEntities is passed in
|
||||||
collections: initPageResult.visibleEntities?.collections,
|
collections: initPageResult?.visibleEntities?.collections,
|
||||||
globals: initPageResult.visibleEntities?.globals,
|
globals: initPageResult?.visibleEntities?.globals,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{RenderedView}
|
{RenderedView}
|
||||||
|
|||||||
@@ -2,37 +2,8 @@
|
|||||||
|
|
||||||
@layer payload-default {
|
@layer payload-default {
|
||||||
.unauthorized {
|
.unauthorized {
|
||||||
margin-top: var(--base);
|
|
||||||
|
|
||||||
& > * {
|
|
||||||
&:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__button {
|
&__button {
|
||||||
margin: 0;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import type { AdminViewComponent, PayloadServerReactComponent } from 'payload'
|
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 LinkImport from 'next/link.js'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
|
import { FormHeader } from '../../elements/FormHeader/index.js'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
|
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
|
||||||
@@ -23,24 +25,31 @@ export const UnauthorizedView: PayloadServerReactComponent<AdminViewComponent> =
|
|||||||
admin: {
|
admin: {
|
||||||
routes: { logout: logoutRoute },
|
routes: { logout: logoutRoute },
|
||||||
},
|
},
|
||||||
|
routes: { admin: adminRoute },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} = initPageResult
|
} = initPageResult
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Gutter className={baseClass}>
|
<div className={baseClass}>
|
||||||
<h2>{i18n.t('error:unauthorized')}</h2>
|
<FormHeader
|
||||||
<p>{i18n.t('error:notAllowedToAccessPage')}</p>
|
description={i18n.t('error:notAllowedToAccessPage')}
|
||||||
|
heading={i18n.t('error:unauthorized')}
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className={`${baseClass}__button`}
|
className={`${baseClass}__button`}
|
||||||
el="link"
|
el="link"
|
||||||
Link={Link}
|
Link={Link}
|
||||||
size="large"
|
size="large"
|
||||||
to={logoutRoute}
|
to={formatAdminURL({
|
||||||
|
adminRoute,
|
||||||
|
path: logoutRoute,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
{i18n.t('authentication:logOut')}
|
{i18n.t('authentication:logOut')}
|
||||||
</Button>
|
</Button>
|
||||||
</Gutter>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
32
packages/next/src/views/Verify/index.client.tsx
Normal file
32
packages/next/src/views/Verify/index.client.tsx
Normal file
@@ -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
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { AdminViewProps } from 'payload'
|
import type { AdminViewProps } from 'payload'
|
||||||
|
|
||||||
import { formatAdminURL } from '@payloadcms/ui/shared'
|
import { formatAdminURL } from '@payloadcms/ui/shared'
|
||||||
import { redirect } from 'next/navigation.js'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { Logo } from '../../elements/Logo/index.js'
|
import { Logo } from '../../elements/Logo/index.js'
|
||||||
|
import { ToastAndRedirect } from './index.client.js'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
export const verifyBaseClass = 'verify'
|
export const verifyBaseClass = 'verify'
|
||||||
@@ -33,6 +33,7 @@ export const Verify: React.FC<AdminViewProps> = async ({
|
|||||||
} = config
|
} = config
|
||||||
|
|
||||||
let textToRender
|
let textToRender
|
||||||
|
let isVerified = false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await req.payload.verifyEmail({
|
await req.payload.verifyEmail({
|
||||||
@@ -40,15 +41,21 @@ export const Verify: React.FC<AdminViewProps> = async ({
|
|||||||
token,
|
token,
|
||||||
})
|
})
|
||||||
|
|
||||||
return redirect(formatAdminURL({ adminRoute, path: '/login' }))
|
isVerified = true
|
||||||
|
textToRender = req.t('authentication:emailVerified')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// already verified
|
|
||||||
if (e?.status === 202) {
|
|
||||||
redirect(formatAdminURL({ adminRoute, path: '/login' }))
|
|
||||||
}
|
|
||||||
textToRender = req.t('authentication:unableToVerify')
|
textToRender = req.t('authentication:unableToVerify')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isVerified) {
|
||||||
|
return (
|
||||||
|
<ToastAndRedirect
|
||||||
|
message={req.t('authentication:emailVerified')}
|
||||||
|
redirectTo={formatAdminURL({ adminRoute, path: '/login' })}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className={`${verifyBaseClass}__brand`}>
|
<div className={`${verifyBaseClass}__brand`}>
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export type InitPageResult = {
|
|||||||
languageOptions: LanguageOptions
|
languageOptions: LanguageOptions
|
||||||
locale?: Locale
|
locale?: Locale
|
||||||
permissions: Permissions
|
permissions: Permissions
|
||||||
|
redirectTo?: string
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
translations: ClientTranslationsObject
|
translations: ClientTranslationsObject
|
||||||
visibleEntities: VisibleEntities
|
visibleEntities: VisibleEntities
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { Payload } from '../index.js'
|
|
||||||
import type { SanitizedCollectionConfig } from './../collections/config/types.js'
|
import type { SanitizedCollectionConfig } from './../collections/config/types.js'
|
||||||
|
|
||||||
type CookieOptions = {
|
type CookieOptions = {
|
||||||
@@ -125,63 +124,63 @@ export const getCookieExpiration = ({ seconds = 7200 }: GetCookieExpirationArgs)
|
|||||||
|
|
||||||
type GeneratePayloadCookieArgs = {
|
type GeneratePayloadCookieArgs = {
|
||||||
/* The auth collection config */
|
/* The auth collection config */
|
||||||
collectionConfig: SanitizedCollectionConfig
|
collectionAuthConfig: SanitizedCollectionConfig['auth']
|
||||||
/* An instance of payload */
|
/* Prefix to scope the cookie */
|
||||||
payload: Payload
|
cookiePrefix: string
|
||||||
/* The returnAs value */
|
/* The returnAs value */
|
||||||
returnCookieAsObject?: boolean
|
returnCookieAsObject?: boolean
|
||||||
/* The token to be stored in the cookie */
|
/* The token to be stored in the cookie */
|
||||||
token: string
|
token: string
|
||||||
}
|
}
|
||||||
export const generatePayloadCookie = <T extends GeneratePayloadCookieArgs>({
|
export const generatePayloadCookie = <T extends GeneratePayloadCookieArgs>({
|
||||||
collectionConfig,
|
collectionAuthConfig,
|
||||||
payload,
|
cookiePrefix,
|
||||||
returnCookieAsObject = false,
|
returnCookieAsObject = false,
|
||||||
token,
|
token,
|
||||||
}: T): T['returnCookieAsObject'] extends true ? CookieObject : string => {
|
}: T): T['returnCookieAsObject'] extends true ? CookieObject : string => {
|
||||||
const sameSite =
|
const sameSite =
|
||||||
typeof collectionConfig.auth.cookies.sameSite === 'string'
|
typeof collectionAuthConfig.cookies.sameSite === 'string'
|
||||||
? collectionConfig.auth.cookies.sameSite
|
? collectionAuthConfig.cookies.sameSite
|
||||||
: collectionConfig.auth.cookies.sameSite
|
: collectionAuthConfig.cookies.sameSite
|
||||||
? 'Strict'
|
? 'Strict'
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
return generateCookie<T['returnCookieAsObject']>({
|
return generateCookie<T['returnCookieAsObject']>({
|
||||||
name: `${payload.config.cookiePrefix}-token`,
|
name: `${cookiePrefix}-token`,
|
||||||
domain: collectionConfig.auth.cookies.domain ?? undefined,
|
domain: collectionAuthConfig.cookies.domain ?? undefined,
|
||||||
expires: getCookieExpiration({ seconds: collectionConfig.auth.tokenExpiration }),
|
expires: getCookieExpiration({ seconds: collectionAuthConfig.tokenExpiration }),
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
path: '/',
|
path: '/',
|
||||||
returnCookieAsObject,
|
returnCookieAsObject,
|
||||||
sameSite,
|
sameSite,
|
||||||
secure: collectionConfig.auth.cookies.secure,
|
secure: collectionAuthConfig.cookies.secure,
|
||||||
value: token,
|
value: token,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateExpiredPayloadCookie = <T extends Omit<GeneratePayloadCookieArgs, 'token'>>({
|
export const generateExpiredPayloadCookie = <T extends Omit<GeneratePayloadCookieArgs, 'token'>>({
|
||||||
collectionConfig,
|
collectionAuthConfig,
|
||||||
payload,
|
cookiePrefix,
|
||||||
returnCookieAsObject = false,
|
returnCookieAsObject = false,
|
||||||
}: T): T['returnCookieAsObject'] extends true ? CookieObject : string => {
|
}: T): T['returnCookieAsObject'] extends true ? CookieObject : string => {
|
||||||
const sameSite =
|
const sameSite =
|
||||||
typeof collectionConfig.auth.cookies.sameSite === 'string'
|
typeof collectionAuthConfig.cookies.sameSite === 'string'
|
||||||
? collectionConfig.auth.cookies.sameSite
|
? collectionAuthConfig.cookies.sameSite
|
||||||
: collectionConfig.auth.cookies.sameSite
|
: collectionAuthConfig.cookies.sameSite
|
||||||
? 'Strict'
|
? 'Strict'
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
const expires = new Date(Date.now() - 1000)
|
const expires = new Date(Date.now() - 1000)
|
||||||
|
|
||||||
return generateCookie<T['returnCookieAsObject']>({
|
return generateCookie<T['returnCookieAsObject']>({
|
||||||
name: `${payload.config.cookiePrefix}-token`,
|
name: `${cookiePrefix}-token`,
|
||||||
domain: collectionConfig.auth.cookies.domain ?? undefined,
|
domain: collectionAuthConfig.cookies.domain ?? undefined,
|
||||||
expires,
|
expires,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
path: '/',
|
path: '/',
|
||||||
returnCookieAsObject,
|
returnCookieAsObject,
|
||||||
sameSite,
|
sameSite,
|
||||||
secure: collectionConfig.auth.cookies.secure,
|
secure: collectionAuthConfig.cookies.secure,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export const resetPasswordOperation = async (args: Arguments): Promise<Result> =
|
|||||||
user.resetPasswordExpiration = new Date().toISOString()
|
user.resetPasswordExpiration = new Date().toISOString()
|
||||||
|
|
||||||
if (collectionConfig.auth.verify) {
|
if (collectionConfig.auth.verify) {
|
||||||
user._verified = true
|
user._verified = Boolean(user._verified)
|
||||||
}
|
}
|
||||||
|
|
||||||
const doc = await payload.db.updateOne({
|
const doc = await payload.db.updateOne({
|
||||||
|
|||||||
@@ -34,9 +34,6 @@ export const verifyEmailOperation = async (args: Args): Promise<boolean> => {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
throw new APIError('Verification token is invalid.', httpStatus.FORBIDDEN)
|
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({
|
await req.payload.db.updateOne({
|
||||||
id: user.id,
|
id: user.id,
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
|
export {
|
||||||
|
generateCookie,
|
||||||
|
generateExpiredPayloadCookie,
|
||||||
|
generatePayloadCookie,
|
||||||
|
getCookieExpiration,
|
||||||
|
parseCookies,
|
||||||
|
} from '../auth/cookies.js'
|
||||||
export { parsePayloadComponent } from '../bin/generateImportMap/parsePayloadComponent.js'
|
export { parsePayloadComponent } from '../bin/generateImportMap/parsePayloadComponent.js'
|
||||||
export { defaults as collectionDefaults } from '../collections/config/defaults.js'
|
export { defaults as collectionDefaults } from '../collections/config/defaults.js'
|
||||||
|
|
||||||
export { serverProps } from '../config/types.js'
|
export { serverProps } from '../config/types.js'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -20,19 +28,19 @@ export {
|
|||||||
tabHasName,
|
tabHasName,
|
||||||
valueIsValueWithRelation,
|
valueIsValueWithRelation,
|
||||||
} from '../fields/config/types.js'
|
} from '../fields/config/types.js'
|
||||||
|
|
||||||
export * from '../fields/validations.js'
|
export * from '../fields/validations.js'
|
||||||
|
|
||||||
export { validOperators } from '../types/constants.js'
|
export { validOperators } from '../types/constants.js'
|
||||||
|
|
||||||
export { formatFilesize } from '../uploads/formatFilesize.js'
|
export { formatFilesize } from '../uploads/formatFilesize.js'
|
||||||
|
|
||||||
export { isImage } from '../uploads/isImage.js'
|
export { isImage } from '../uploads/isImage.js'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
deepCopyObject,
|
deepCopyObject,
|
||||||
deepCopyObjectComplex,
|
deepCopyObjectComplex,
|
||||||
deepCopyObjectSimple,
|
deepCopyObjectSimple,
|
||||||
} from '../utilities/deepCopyObject.js'
|
} from '../utilities/deepCopyObject.js'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
deepMerge,
|
deepMerge,
|
||||||
deepMergeWithCombinedArrays,
|
deepMergeWithCombinedArrays,
|
||||||
@@ -41,8 +49,8 @@ export {
|
|||||||
} from '../utilities/deepMerge.js'
|
} from '../utilities/deepMerge.js'
|
||||||
|
|
||||||
export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON.js'
|
export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON.js'
|
||||||
|
|
||||||
export { getDataByPath } from '../utilities/getDataByPath.js'
|
export { getDataByPath } from '../utilities/getDataByPath.js'
|
||||||
|
|
||||||
export { getSiblingData } from '../utilities/getSiblingData.js'
|
export { getSiblingData } from '../utilities/getSiblingData.js'
|
||||||
|
|
||||||
export { getUniqueListBy } from '../utilities/getUniqueListBy.js'
|
export { getUniqueListBy } from '../utilities/getUniqueListBy.js'
|
||||||
@@ -66,6 +74,5 @@ export { unflatten } from '../utilities/unflatten.js'
|
|||||||
export { wait } from '../utilities/wait.js'
|
export { wait } from '../utilities/wait.js'
|
||||||
|
|
||||||
export { default as wordBoundariesRegex } from '../utilities/wordBoundariesRegex.js'
|
export { default as wordBoundariesRegex } from '../utilities/wordBoundariesRegex.js'
|
||||||
|
|
||||||
export { versionDefaults } from '../versions/defaults.js'
|
export { versionDefaults } from '../versions/defaults.js'
|
||||||
export { deepMergeSimple } from '@payloadcms/translations/utilities'
|
export { deepMergeSimple } from '@payloadcms/translations/utilities'
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ export const arTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'العودة للوحة التّحكّم',
|
backToDashboard: 'العودة للوحة التّحكّم',
|
||||||
cancel: 'إلغاء',
|
cancel: 'إلغاء',
|
||||||
changesNotSaved: 'لم يتمّ حفظ التّغييرات. إن غادرت الآن ، ستفقد تغييراتك.',
|
changesNotSaved: 'لم يتمّ حفظ التّغييرات. إن غادرت الآن ، ستفقد تغييراتك.',
|
||||||
clearAll: undefined,
|
clearAll: 'امسح الكل',
|
||||||
close: 'إغلاق',
|
close: 'إغلاق',
|
||||||
collapse: 'طيّ',
|
collapse: 'طيّ',
|
||||||
collections: 'المجموعات',
|
collections: 'المجموعات',
|
||||||
@@ -407,7 +407,7 @@ export const arTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'تم الحفظ آخر مرة قبل {{distance}}',
|
lastSavedAgo: 'تم الحفظ آخر مرة قبل {{distance}}',
|
||||||
noFurtherVersionsFound: 'لم يتمّ العثور على نسخات أخرى',
|
noFurtherVersionsFound: 'لم يتمّ العثور على نسخات أخرى',
|
||||||
noRowsFound: 'لم يتمّ العثور على {{label}}',
|
noRowsFound: 'لم يتمّ العثور على {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'لم يتم اختيار {{label}}',
|
||||||
preview: 'معاينة',
|
preview: 'معاينة',
|
||||||
previouslyPublished: 'نشر سابقا',
|
previouslyPublished: 'نشر سابقا',
|
||||||
problemRestoringVersion: 'حدث خطأ في استعادة هذه النّسخة',
|
problemRestoringVersion: 'حدث خطأ في استعادة هذه النّسخة',
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export const azTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Ləğv et',
|
cancel: 'Ləğv et',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Dəyişiklikləriniz saxlanılmayıb. İndi çıxsanız, dəyişikliklərinizi itirəcəksiniz.',
|
'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',
|
close: 'Bağla',
|
||||||
collapse: 'Bağla',
|
collapse: 'Bağla',
|
||||||
collections: 'Kolleksiyalar',
|
collections: 'Kolleksiyalar',
|
||||||
@@ -414,7 +414,7 @@ export const azTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: '{{distance}} əvvəl son yadda saxlanıldı',
|
lastSavedAgo: '{{distance}} əvvəl son yadda saxlanıldı',
|
||||||
noFurtherVersionsFound: 'Başqa versiyalar tapılmadı',
|
noFurtherVersionsFound: 'Başqa versiyalar tapılmadı',
|
||||||
noRowsFound: 'Heç bir {{label}} tapılmadı',
|
noRowsFound: 'Heç bir {{label}} tapılmadı',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Heç bir {{label}} seçilməyib',
|
||||||
preview: 'Öncədən baxış',
|
preview: 'Öncədən baxış',
|
||||||
previouslyPublished: 'Daha əvvəl nəşr olunmuş',
|
previouslyPublished: 'Daha əvvəl nəşr olunmuş',
|
||||||
problemRestoringVersion: 'Bu versiyanın bərpasında problem yaşandı',
|
problemRestoringVersion: 'Bu versiyanın bərpasında problem yaşandı',
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export const bgTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'Обратно към таблото',
|
backToDashboard: 'Обратно към таблото',
|
||||||
cancel: 'Отмени',
|
cancel: 'Отмени',
|
||||||
changesNotSaved: 'Промените ти не са запазени. Ако напуснеш сега, ще ги загубиш.',
|
changesNotSaved: 'Промените ти не са запазени. Ако напуснеш сега, ще ги загубиш.',
|
||||||
clearAll: undefined,
|
clearAll: 'Изчисти всичко',
|
||||||
close: 'Затвори',
|
close: 'Затвори',
|
||||||
collapse: 'Свий',
|
collapse: 'Свий',
|
||||||
collections: 'Колекции',
|
collections: 'Колекции',
|
||||||
@@ -413,7 +413,7 @@ export const bgTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'последно запазено преди {{distance}}',
|
lastSavedAgo: 'последно запазено преди {{distance}}',
|
||||||
noFurtherVersionsFound: 'Не са открити повече версии',
|
noFurtherVersionsFound: 'Не са открити повече версии',
|
||||||
noRowsFound: 'Не е открит {{label}}',
|
noRowsFound: 'Не е открит {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Не е избран {{label}}',
|
||||||
preview: 'Предварителен преглед',
|
preview: 'Предварителен преглед',
|
||||||
previouslyPublished: 'Предишно публикувано',
|
previouslyPublished: 'Предишно публикувано',
|
||||||
problemRestoringVersion: 'Имаше проблем при възстановяването на тази версия',
|
problemRestoringVersion: 'Имаше проблем при възстановяването на тази версия',
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export const csTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'Zpět na nástěnku',
|
backToDashboard: 'Zpět na nástěnku',
|
||||||
cancel: 'Zrušit',
|
cancel: 'Zrušit',
|
||||||
changesNotSaved: 'Vaše změny nebyly uloženy. Pokud teď odejdete, ztratíte své změny.',
|
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',
|
close: 'Zavřít',
|
||||||
collapse: 'Sbalit',
|
collapse: 'Sbalit',
|
||||||
collections: 'Kolekce',
|
collections: 'Kolekce',
|
||||||
@@ -412,7 +412,7 @@ export const csTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Naposledy uloženo před {{distance}}',
|
lastSavedAgo: 'Naposledy uloženo před {{distance}}',
|
||||||
noFurtherVersionsFound: 'Nenalezeny další verze',
|
noFurtherVersionsFound: 'Nenalezeny další verze',
|
||||||
noRowsFound: 'Nenalezen {{label}}',
|
noRowsFound: 'Nenalezen {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nebyl vybrán žádný {{label}}',
|
||||||
preview: 'Náhled',
|
preview: 'Náhled',
|
||||||
previouslyPublished: 'Dříve publikováno',
|
previouslyPublished: 'Dříve publikováno',
|
||||||
problemRestoringVersion: 'Při obnovování této verze došlo k problému',
|
problemRestoringVersion: 'Při obnovování této verze došlo k problému',
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ export const deTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Abbrechen',
|
cancel: 'Abbrechen',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Deine Änderungen wurden nicht gespeichert. Wenn du diese Seite verlässt, gehen deine Änderungen verloren.',
|
'Deine Änderungen wurden nicht gespeichert. Wenn du diese Seite verlässt, gehen deine Änderungen verloren.',
|
||||||
clearAll: undefined,
|
clearAll: 'Alles löschen',
|
||||||
close: 'Schließen',
|
close: 'Schließen',
|
||||||
collapse: 'Einklappen',
|
collapse: 'Einklappen',
|
||||||
collections: 'Sammlungen',
|
collections: 'Sammlungen',
|
||||||
@@ -418,7 +418,7 @@ export const deTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Zuletzt vor {{distance}} gespeichert',
|
lastSavedAgo: 'Zuletzt vor {{distance}} gespeichert',
|
||||||
noFurtherVersionsFound: 'Keine weiteren Versionen vorhanden',
|
noFurtherVersionsFound: 'Keine weiteren Versionen vorhanden',
|
||||||
noRowsFound: 'Kein {{label}} gefunden',
|
noRowsFound: 'Kein {{label}} gefunden',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Kein {{label}} ausgewählt',
|
||||||
preview: 'Vorschau',
|
preview: 'Vorschau',
|
||||||
previouslyPublished: 'Zuvor Veröffentlicht',
|
previouslyPublished: 'Zuvor Veröffentlicht',
|
||||||
problemRestoringVersion: 'Es gab ein Problem bei der Wiederherstellung dieser Version',
|
problemRestoringVersion: 'Es gab ein Problem bei der Wiederherstellung dieser Version',
|
||||||
|
|||||||
@@ -66,9 +66,8 @@ export const enTranslations = {
|
|||||||
successfullyRegisteredFirstUser: 'Successfully registered first user.',
|
successfullyRegisteredFirstUser: 'Successfully registered first user.',
|
||||||
successfullyUnlocked: 'Successfully unlocked',
|
successfullyUnlocked: 'Successfully unlocked',
|
||||||
tokenRefreshSuccessful: 'Token refresh successful.',
|
tokenRefreshSuccessful: 'Token refresh successful.',
|
||||||
username: 'Username',
|
|
||||||
|
|
||||||
unableToVerify: 'Unable to Verify',
|
unableToVerify: 'Unable to Verify',
|
||||||
|
username: 'Username',
|
||||||
verified: 'Verified',
|
verified: 'Verified',
|
||||||
verifiedSuccessfully: 'Verified Successfully',
|
verifiedSuccessfully: 'Verified Successfully',
|
||||||
verify: 'Verify',
|
verify: 'Verify',
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ export const esTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Cancelar',
|
cancel: 'Cancelar',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Tus cambios no han sido guardados. Si te sales ahora, se perderán tus cambios.',
|
'Tus cambios no han sido guardados. Si te sales ahora, se perderán tus cambios.',
|
||||||
clearAll: undefined,
|
clearAll: 'Borrar todo',
|
||||||
close: 'Cerrar',
|
close: 'Cerrar',
|
||||||
collapse: 'Colapsar',
|
collapse: 'Colapsar',
|
||||||
collections: 'Colecciones',
|
collections: 'Colecciones',
|
||||||
@@ -418,7 +418,7 @@ export const esTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Guardado por última vez hace {{distance}}',
|
lastSavedAgo: 'Guardado por última vez hace {{distance}}',
|
||||||
noFurtherVersionsFound: 'No se encontraron más versiones',
|
noFurtherVersionsFound: 'No se encontraron más versiones',
|
||||||
noRowsFound: 'No encontramos {{label}}',
|
noRowsFound: 'No encontramos {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'No se ha seleccionado ninguna {{etiqueta}}',
|
||||||
preview: 'Previsualizar',
|
preview: 'Previsualizar',
|
||||||
previouslyPublished: 'Publicado Anteriormente',
|
previouslyPublished: 'Publicado Anteriormente',
|
||||||
problemRestoringVersion: 'Ocurrió un problema al restaurar esta versión',
|
problemRestoringVersion: 'Ocurrió un problema al restaurar esta versión',
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export const faTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'لغو',
|
cancel: 'لغو',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'تغییرات شما ذخیره نشده، اگر این برگه را ترک کنید. تمام تغییرات از دست خواهد رفت.',
|
'تغییرات شما ذخیره نشده، اگر این برگه را ترک کنید. تمام تغییرات از دست خواهد رفت.',
|
||||||
clearAll: undefined,
|
clearAll: 'همه را پاک کنید',
|
||||||
close: 'بستن',
|
close: 'بستن',
|
||||||
collapse: 'بستن',
|
collapse: 'بستن',
|
||||||
collections: 'مجموعهها',
|
collections: 'مجموعهها',
|
||||||
@@ -411,7 +411,7 @@ export const faTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'آخرین بار {{distance}} پیش ذخیره شد',
|
lastSavedAgo: 'آخرین بار {{distance}} پیش ذخیره شد',
|
||||||
noFurtherVersionsFound: 'نگارش دیگری یافت نشد',
|
noFurtherVersionsFound: 'نگارش دیگری یافت نشد',
|
||||||
noRowsFound: 'هیچ {{label}} یافت نشد',
|
noRowsFound: 'هیچ {{label}} یافت نشد',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'هیچ {{label}} ای انتخاب نشده است',
|
||||||
preview: 'پیشنمایش',
|
preview: 'پیشنمایش',
|
||||||
previouslyPublished: 'قبلا منتشر شده',
|
previouslyPublished: 'قبلا منتشر شده',
|
||||||
problemRestoringVersion: 'مشکلی در بازیابی این نگارش وجود دارد',
|
problemRestoringVersion: 'مشکلی در بازیابی این نگارش وجود دارد',
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ export const frTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Annuler',
|
cancel: 'Annuler',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Vos modifications n’ont pas été enregistrées. Vous perdrez vos modifications si vous quittez maintenant.',
|
'Vos modifications n’ont pas été enregistrées. Vous perdrez vos modifications si vous quittez maintenant.',
|
||||||
clearAll: undefined,
|
clearAll: 'Tout effacer',
|
||||||
close: 'Fermer',
|
close: 'Fermer',
|
||||||
collapse: 'Réduire',
|
collapse: 'Réduire',
|
||||||
collections: 'Collections',
|
collections: 'Collections',
|
||||||
@@ -425,7 +425,7 @@ export const frTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Dernière sauvegarde il y a {{distance}}',
|
lastSavedAgo: 'Dernière sauvegarde il y a {{distance}}',
|
||||||
noFurtherVersionsFound: 'Aucune autre version trouvée',
|
noFurtherVersionsFound: 'Aucune autre version trouvée',
|
||||||
noRowsFound: 'Aucun(e) {{label}} trouvé(e)',
|
noRowsFound: 'Aucun(e) {{label}} trouvé(e)',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Aucune {{étiquette}} sélectionnée',
|
||||||
preview: 'Aperçu',
|
preview: 'Aperçu',
|
||||||
previouslyPublished: 'Précédemment publié',
|
previouslyPublished: 'Précédemment publié',
|
||||||
problemRestoringVersion: 'Un problème est survenu lors de la restauration de cette version',
|
problemRestoringVersion: 'Un problème est survenu lors de la restauration de cette version',
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ export const heTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'חזרה ללוח המחוונים',
|
backToDashboard: 'חזרה ללוח המחוונים',
|
||||||
cancel: 'ביטול',
|
cancel: 'ביטול',
|
||||||
changesNotSaved: 'השינויים שלך לא נשמרו. אם תצא כעת, תאבד את השינויים שלך.',
|
changesNotSaved: 'השינויים שלך לא נשמרו. אם תצא כעת, תאבד את השינויים שלך.',
|
||||||
clearAll: undefined,
|
clearAll: 'נקה הכל',
|
||||||
close: 'סגור',
|
close: 'סגור',
|
||||||
collapse: 'כווץ',
|
collapse: 'כווץ',
|
||||||
collections: 'אוספים',
|
collections: 'אוספים',
|
||||||
@@ -260,7 +260,7 @@ export const heTranslations: DefaultTranslationsObject = {
|
|||||||
nothingFound: 'לא נמצא כלום',
|
nothingFound: 'לא נמצא כלום',
|
||||||
noValue: 'אין ערך',
|
noValue: 'אין ערך',
|
||||||
of: 'מתוך',
|
of: 'מתוך',
|
||||||
only: undefined,
|
only: 'רק',
|
||||||
open: 'פתח',
|
open: 'פתח',
|
||||||
or: 'או',
|
or: 'או',
|
||||||
order: 'סדר',
|
order: 'סדר',
|
||||||
@@ -401,7 +401,7 @@ export const heTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'נשמר לאחרונה לפני {{distance}}',
|
lastSavedAgo: 'נשמר לאחרונה לפני {{distance}}',
|
||||||
noFurtherVersionsFound: 'לא נמצאו עוד גרסאות',
|
noFurtherVersionsFound: 'לא נמצאו עוד גרסאות',
|
||||||
noRowsFound: 'לא נמצאו {{label}}',
|
noRowsFound: 'לא נמצאו {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'לא נבחר {{תווית}}',
|
||||||
preview: 'תצוגה מקדימה',
|
preview: 'תצוגה מקדימה',
|
||||||
previouslyPublished: 'פורסם בעבר',
|
previouslyPublished: 'פורסם בעבר',
|
||||||
problemRestoringVersion: 'הייתה בעיה בשחזור הגרסה הזו',
|
problemRestoringVersion: 'הייתה בעיה בשחזור הגרסה הזו',
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ export const hrTranslations: DefaultTranslationsObject = {
|
|||||||
generateNewAPIKey: 'Generiraj novi API ključ',
|
generateNewAPIKey: 'Generiraj novi API ključ',
|
||||||
generatingNewAPIKeyWillInvalidate:
|
generatingNewAPIKeyWillInvalidate:
|
||||||
'Generiranje novog API ključa će <1>poništiti</1> prethodni ključ. Jeste li sigurni da želite nastaviti?',
|
'Generiranje novog API ključa će <1>poništiti</1> prethodni ključ. Jeste li sigurni da želite nastaviti?',
|
||||||
newAPIKeyGenerated: 'New API ključ generiran.',
|
|
||||||
lockUntil: 'Zaključaj dok',
|
lockUntil: 'Zaključaj dok',
|
||||||
logBackIn: 'Ponovno se prijavite',
|
logBackIn: 'Ponovno se prijavite',
|
||||||
loggedIn: 'Za prijavu s drugim korisničkim računom potrebno je prvo <0>odjaviti se</0>',
|
loggedIn: 'Za prijavu s drugim korisničkim računom potrebno je prvo <0>odjaviti se</0>',
|
||||||
@@ -53,7 +52,8 @@ export const hrTranslations: DefaultTranslationsObject = {
|
|||||||
logoutSuccessful: 'Odjava uspješna.',
|
logoutSuccessful: 'Odjava uspješna.',
|
||||||
logoutUser: 'Odjava korisnika',
|
logoutUser: 'Odjava korisnika',
|
||||||
newAccountCreated:
|
newAccountCreated:
|
||||||
'Novi račun je izrađen. Pristupite računu klikom na: <a href="{{serverURL}}">{{serverURL}}</a>. Molimo kliknite na sljedeću poveznicu ili zalijepite URL, koji se nalazi ispod, u preglednik da biste potvrdili svoju e-mail adresu: <a href="{{verificationURL}}">{{verificationURL}}</a><br> Nakon što potvrdite e-mail adresu, moći ćete se prijaviti.',
|
'Novi račun je izrađen. Pristupite računu klikom na: <a href="{{serverURL}}">{{serverURL}}</a>. Molimo kliknite na sljedeću poveznicu ili zalijepite URL, koji se nalazi ispod, u preglednik da biste potvrdili svoju e-mail adresu: <a href="{{verificationURL}}">{{verificationURL}}</a><br> Nakon što potvrdite e-mail adresu, moći ćete se prijaviti.',
|
||||||
|
newAPIKeyGenerated: 'New API ključ generiran.',
|
||||||
newPassword: 'Nova lozinka',
|
newPassword: 'Nova lozinka',
|
||||||
passed: 'Autentifikacija je prošla',
|
passed: 'Autentifikacija je prošla',
|
||||||
passwordResetSuccessfully: 'Lozinka uspješno resetirana.',
|
passwordResetSuccessfully: 'Lozinka uspješno resetirana.',
|
||||||
@@ -111,11 +111,11 @@ export const hrTranslations: DefaultTranslationsObject = {
|
|||||||
problemUploadingFile: 'Došlo je do problema pri učitavanju datoteke.',
|
problemUploadingFile: 'Došlo je do problema pri učitavanju datoteke.',
|
||||||
tokenInvalidOrExpired: 'Token je neispravan ili je istekao.',
|
tokenInvalidOrExpired: 'Token je neispravan ili je istekao.',
|
||||||
tokenNotProvided: 'Token nije pružen.',
|
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}}.',
|
unableToDeleteCount: 'Nije moguće izbrisati {{count}} od {{total}} {{label}}.',
|
||||||
unableToUpdateCount: 'Nije moguće ažurirati {{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.',
|
unauthorized: 'Neovlašteno, morate biti prijavljeni da biste uputili ovaj zahtjev.',
|
||||||
unknown: 'Došlo je do nepoznate pogreške.',
|
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.',
|
unspecific: 'Došlo je do pogreške.',
|
||||||
userEmailAlreadyRegistered: 'Korisnik s navedenom e-mail adresom je već registriran.',
|
userEmailAlreadyRegistered: 'Korisnik s navedenom e-mail adresom je već registriran.',
|
||||||
userLocked: 'Ovaj korisnik je zaključan zbog previše neuspješnih pokušaja prijave.',
|
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',
|
backToDashboard: 'Natrag na nadzornu ploču',
|
||||||
cancel: 'Otkaži',
|
cancel: 'Otkaži',
|
||||||
changesNotSaved: 'Vaše promjene nisu spremljene. Ako izađete sada, izgubit ćete promjene.',
|
changesNotSaved: 'Vaše promjene nisu spremljene. Ako izađete sada, izgubit ćete promjene.',
|
||||||
clearAll: undefined,
|
clearAll: 'Očisti sve',
|
||||||
close: 'Zatvori',
|
close: 'Zatvori',
|
||||||
collapse: 'Sažmi',
|
collapse: 'Sažmi',
|
||||||
collections: 'Kolekcije',
|
collections: 'Kolekcije',
|
||||||
@@ -258,11 +258,12 @@ export const hrTranslations: DefaultTranslationsObject = {
|
|||||||
next: 'Sljedeće',
|
next: 'Sljedeće',
|
||||||
noFiltersSet: 'Nema postavljenih filtera',
|
noFiltersSet: 'Nema postavljenih filtera',
|
||||||
noLabel: '<Nema {{label}}>',
|
noLabel: '<Nema {{label}}>',
|
||||||
notFound: 'Nije pronađeno',
|
|
||||||
nothingFound: 'Ništa nije pronađeno',
|
|
||||||
none: 'Nijedan',
|
none: 'Nijedan',
|
||||||
noOptions: 'Nema opcija',
|
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',
|
noValue: 'Bez vrijednosti',
|
||||||
of: 'od',
|
of: 'od',
|
||||||
only: 'Samo',
|
only: 'Samo',
|
||||||
@@ -410,14 +411,14 @@ export const hrTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Zadnji put spremljeno prije {{distance}',
|
lastSavedAgo: 'Zadnji put spremljeno prije {{distance}',
|
||||||
noFurtherVersionsFound: 'Nisu pronađene daljnje verzije',
|
noFurtherVersionsFound: 'Nisu pronađene daljnje verzije',
|
||||||
noRowsFound: '{{label}} nije pronađeno',
|
noRowsFound: '{{label}} nije pronađeno',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nije odabrana {{oznaka}}',
|
||||||
preview: 'Pregled',
|
preview: 'Pregled',
|
||||||
previouslyPublished: 'Prethodno objavljeno',
|
previouslyPublished: 'Prethodno objavljeno',
|
||||||
problemRestoringVersion: 'Nastao je problem pri vraćanju ove verzije',
|
problemRestoringVersion: 'Nastao je problem pri vraćanju ove verzije',
|
||||||
publish: 'Objaviti',
|
publish: 'Objaviti',
|
||||||
publishChanges: 'Objavi promjene',
|
publishChanges: 'Objavi promjene',
|
||||||
published: 'Objavljeno',
|
published: 'Objavljeno',
|
||||||
publishIn: undefined,
|
publishIn: 'Objavi na {{locale}}',
|
||||||
publishing: 'Objavljivanje',
|
publishing: 'Objavljivanje',
|
||||||
restoreAsDraft: 'Vrati kao skicu',
|
restoreAsDraft: 'Vrati kao skicu',
|
||||||
restoredSuccessfully: 'Uspješno vraćeno.',
|
restoredSuccessfully: 'Uspješno vraćeno.',
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ export const huTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Mégsem',
|
cancel: 'Mégsem',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'A módosítások nem lettek mentve. Ha most távozik, elveszíti a változtatásokat.',
|
'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',
|
close: 'Bezárás',
|
||||||
collapse: 'Összecsukás',
|
collapse: 'Összecsukás',
|
||||||
collections: 'Gyűjtemények',
|
collections: 'Gyűjtemények',
|
||||||
@@ -418,7 +418,7 @@ export const huTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Utoljára mentve {{distance}} órája',
|
lastSavedAgo: 'Utoljára mentve {{distance}} órája',
|
||||||
noFurtherVersionsFound: 'További verziók nem találhatók',
|
noFurtherVersionsFound: 'További verziók nem találhatók',
|
||||||
noRowsFound: 'Nem található {{label}}',
|
noRowsFound: 'Nem található {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nincs {{címke}} kiválasztva',
|
||||||
preview: 'Előnézet',
|
preview: 'Előnézet',
|
||||||
previouslyPublished: 'Korábban Közzétéve',
|
previouslyPublished: 'Korábban Közzétéve',
|
||||||
problemRestoringVersion: 'Hiba történt a verzió visszaállításakor',
|
problemRestoringVersion: 'Hiba történt a verzió visszaállításakor',
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ export const itTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'Torna alla Dashboard',
|
backToDashboard: 'Torna alla Dashboard',
|
||||||
cancel: 'Cancella',
|
cancel: 'Cancella',
|
||||||
changesNotSaved: 'Le tue modifiche non sono state salvate. Se esci ora, verranno perse.',
|
changesNotSaved: 'Le tue modifiche non sono state salvate. Se esci ora, verranno perse.',
|
||||||
clearAll: undefined,
|
clearAll: 'Cancella Tutto',
|
||||||
close: 'Chiudere',
|
close: 'Chiudere',
|
||||||
collapse: 'Comprimi',
|
collapse: 'Comprimi',
|
||||||
collections: 'Collezioni',
|
collections: 'Collezioni',
|
||||||
@@ -418,7 +418,7 @@ export const itTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Ultimo salvataggio {{distance}} fa',
|
lastSavedAgo: 'Ultimo salvataggio {{distance}} fa',
|
||||||
noFurtherVersionsFound: 'Non sono state trovate ulteriori versioni',
|
noFurtherVersionsFound: 'Non sono state trovate ulteriori versioni',
|
||||||
noRowsFound: 'Nessun {{label}} trovato',
|
noRowsFound: 'Nessun {{label}} trovato',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nessuna {{etichetta}} selezionata',
|
||||||
preview: 'Anteprima',
|
preview: 'Anteprima',
|
||||||
previouslyPublished: 'Precedentemente Pubblicato',
|
previouslyPublished: 'Precedentemente Pubblicato',
|
||||||
problemRestoringVersion: 'Si è verificato un problema durante il ripristino di questa versione',
|
problemRestoringVersion: 'Si è verificato un problema durante il ripristino di questa versione',
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export const jaTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'ダッシュボードに戻る',
|
backToDashboard: 'ダッシュボードに戻る',
|
||||||
cancel: 'キャンセル',
|
cancel: 'キャンセル',
|
||||||
changesNotSaved: '未保存の変更があります。このまま画面を離れると内容が失われます。',
|
changesNotSaved: '未保存の変更があります。このまま画面を離れると内容が失われます。',
|
||||||
clearAll: undefined,
|
clearAll: 'すべてクリア',
|
||||||
close: '閉じる',
|
close: '閉じる',
|
||||||
collapse: '閉じる',
|
collapse: '閉じる',
|
||||||
collections: 'コレクション',
|
collections: 'コレクション',
|
||||||
@@ -412,7 +412,7 @@ export const jaTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: '{{distance}}前に最後に保存されました',
|
lastSavedAgo: '{{distance}}前に最後に保存されました',
|
||||||
noFurtherVersionsFound: 'その他のバージョンは見つかりませんでした。',
|
noFurtherVersionsFound: 'その他のバージョンは見つかりませんでした。',
|
||||||
noRowsFound: '{{label}} は未設定です',
|
noRowsFound: '{{label}} は未設定です',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: '選択された{{label}}はありません',
|
||||||
preview: 'プレビュー',
|
preview: 'プレビュー',
|
||||||
previouslyPublished: '以前に公開された',
|
previouslyPublished: '以前に公開された',
|
||||||
problemRestoringVersion: 'このバージョンの復元に問題がありました。',
|
problemRestoringVersion: 'このバージョンの復元に問題がありました。',
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export const koTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: '대시보드로 돌아가기',
|
backToDashboard: '대시보드로 돌아가기',
|
||||||
cancel: '취소',
|
cancel: '취소',
|
||||||
changesNotSaved: '변경 사항이 저장되지 않았습니다. 지금 떠나면 변경 사항을 잃게 됩니다.',
|
changesNotSaved: '변경 사항이 저장되지 않았습니다. 지금 떠나면 변경 사항을 잃게 됩니다.',
|
||||||
clearAll: undefined,
|
clearAll: '모두 지우기',
|
||||||
close: '닫기',
|
close: '닫기',
|
||||||
collapse: '접기',
|
collapse: '접기',
|
||||||
collections: '컬렉션',
|
collections: '컬렉션',
|
||||||
@@ -408,7 +408,7 @@ export const koTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: '마지막으로 저장한지 {{distance}} 전',
|
lastSavedAgo: '마지막으로 저장한지 {{distance}} 전',
|
||||||
noFurtherVersionsFound: '더 이상의 버전을 찾을 수 없습니다.',
|
noFurtherVersionsFound: '더 이상의 버전을 찾을 수 없습니다.',
|
||||||
noRowsFound: '{{label}}을(를) 찾을 수 없음',
|
noRowsFound: '{{label}}을(를) 찾을 수 없음',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: '선택된 {{label}} 없음',
|
||||||
preview: '미리보기',
|
preview: '미리보기',
|
||||||
previouslyPublished: '이전에 발표된',
|
previouslyPublished: '이전에 발표된',
|
||||||
problemRestoringVersion: '이 버전을 복원하는 중 문제가 발생했습니다.',
|
problemRestoringVersion: '이 버전을 복원하는 중 문제가 발생했습니다.',
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ export const myTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'မလုပ်တော့ပါ။',
|
cancel: 'မလုပ်တော့ပါ။',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'သင်၏ပြောင်းလဲမှုများကို မသိမ်းဆည်းရသေးပါ။ ယခု စာမျက်နှာက ထွက်လိုက်ပါက သင်၏ပြောင်းလဲမှုများ အကုန် ဆုံးရှုံးသွားပါမည်။ အကုန်နော်။',
|
'သင်၏ပြောင်းလဲမှုများကို မသိမ်းဆည်းရသေးပါ။ ယခု စာမျက်နှာက ထွက်လိုက်ပါက သင်၏ပြောင်းလဲမှုများ အကုန် ဆုံးရှုံးသွားပါမည်။ အကုန်နော်။',
|
||||||
clearAll: undefined,
|
clearAll: 'အားလုံးကိုရှင်းလင်းပါ',
|
||||||
close: 'ပိတ်',
|
close: 'ပိတ်',
|
||||||
collapse: 'ခေါက်သိမ်းပါ။',
|
collapse: 'ခေါက်သိမ်းပါ။',
|
||||||
collections: 'စုစည်းမှူများ',
|
collections: 'စုစည်းမှူများ',
|
||||||
@@ -420,7 +420,7 @@ export const myTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'နောက်ဆုံး သိမ်းချက် {{distance}} ကြာပြီး',
|
lastSavedAgo: 'နောက်ဆုံး သိမ်းချက် {{distance}} ကြာပြီး',
|
||||||
noFurtherVersionsFound: 'နောက်ထပ်ဗားရှင်းများ မတွေ့ပါ။',
|
noFurtherVersionsFound: 'နောက်ထပ်ဗားရှင်းများ မတွေ့ပါ။',
|
||||||
noRowsFound: '{{label}} အားမတွေ့ပါ။',
|
noRowsFound: '{{label}} အားမတွေ့ပါ။',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Tiada {{label}} yang dipilih',
|
||||||
preview: 'နမူနာပြရန်',
|
preview: 'နမူနာပြရန်',
|
||||||
previouslyPublished: 'တိုင်းရင်းသားထုတ်ဝေခဲ့',
|
previouslyPublished: 'တိုင်းရင်းသားထုတ်ဝေခဲ့',
|
||||||
problemRestoringVersion: 'ဤဗားရှင်းကို ပြန်လည်ရယူရာတွင် ပြဿနာရှိနေသည်။',
|
problemRestoringVersion: 'ဤဗားရှင်းကို ပြန်လည်ရယူရာတွင် ပြဿနာရှိနေသည်။',
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export const nbTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Avbryt',
|
cancel: 'Avbryt',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Endringene dine er ikke lagret. Hvis du forlater nå, vil du miste endringene dine.',
|
'Endringene dine er ikke lagret. Hvis du forlater nå, vil du miste endringene dine.',
|
||||||
clearAll: undefined,
|
clearAll: 'Tøm alt',
|
||||||
close: 'Lukk',
|
close: 'Lukk',
|
||||||
collapse: 'Skjul',
|
collapse: 'Skjul',
|
||||||
collections: 'Samlinger',
|
collections: 'Samlinger',
|
||||||
@@ -266,7 +266,7 @@ export const nbTranslations: DefaultTranslationsObject = {
|
|||||||
nothingFound: 'Ingenting funnet',
|
nothingFound: 'Ingenting funnet',
|
||||||
noValue: 'Ingen verdi',
|
noValue: 'Ingen verdi',
|
||||||
of: 'av',
|
of: 'av',
|
||||||
only: undefined,
|
only: 'Bare',
|
||||||
open: 'Åpne',
|
open: 'Åpne',
|
||||||
or: 'Eller',
|
or: 'Eller',
|
||||||
order: 'Rekkefølge',
|
order: 'Rekkefølge',
|
||||||
@@ -414,7 +414,7 @@ export const nbTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Sist lagret {{distance}} siden',
|
lastSavedAgo: 'Sist lagret {{distance}} siden',
|
||||||
noFurtherVersionsFound: 'Ingen flere versjoner funnet',
|
noFurtherVersionsFound: 'Ingen flere versjoner funnet',
|
||||||
noRowsFound: 'Ingen {{label}} funnet',
|
noRowsFound: 'Ingen {{label}} funnet',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Ingen {{label}} valgt',
|
||||||
preview: 'Forhåndsvisning',
|
preview: 'Forhåndsvisning',
|
||||||
previouslyPublished: 'Tidligere Publisert',
|
previouslyPublished: 'Tidligere Publisert',
|
||||||
problemRestoringVersion: 'Det oppstod et problem med gjenoppretting av denne versjonen',
|
problemRestoringVersion: 'Det oppstod et problem med gjenoppretting av denne versjonen',
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ export const nlTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Annuleren',
|
cancel: 'Annuleren',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Uw wijzigingen zijn niet bewaard. Als u weggaat zullen de wijzigingen verloren gaan.',
|
'Uw wijzigingen zijn niet bewaard. Als u weggaat zullen de wijzigingen verloren gaan.',
|
||||||
clearAll: undefined,
|
clearAll: 'Alles wissen',
|
||||||
close: 'Dichtbij',
|
close: 'Dichtbij',
|
||||||
collapse: 'Samenvouwen',
|
collapse: 'Samenvouwen',
|
||||||
collections: 'Collecties',
|
collections: 'Collecties',
|
||||||
@@ -417,7 +417,7 @@ export const nlTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Laatst opgeslagen {{distance}} geleden',
|
lastSavedAgo: 'Laatst opgeslagen {{distance}} geleden',
|
||||||
noFurtherVersionsFound: 'Geen verdere versies gevonden',
|
noFurtherVersionsFound: 'Geen verdere versies gevonden',
|
||||||
noRowsFound: 'Geen {{label}} gevonden',
|
noRowsFound: 'Geen {{label}} gevonden',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Geen {{label}} geselecteerd',
|
||||||
preview: 'Voorbeeld',
|
preview: 'Voorbeeld',
|
||||||
previouslyPublished: 'Eerder gepubliceerd',
|
previouslyPublished: 'Eerder gepubliceerd',
|
||||||
problemRestoringVersion: 'Er was een probleem bij het herstellen van deze versie',
|
problemRestoringVersion: 'Er was een probleem bij het herstellen van deze versie',
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export const plTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Anuluj',
|
cancel: 'Anuluj',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Twoje zmiany nie zostały zapisane. Jeśli teraz wyjdziesz, stracisz swoje zmiany.',
|
'Twoje zmiany nie zostały zapisane. Jeśli teraz wyjdziesz, stracisz swoje zmiany.',
|
||||||
clearAll: undefined,
|
clearAll: 'Wyczyść wszystko',
|
||||||
close: 'Zamknij',
|
close: 'Zamknij',
|
||||||
collapse: 'Zwiń',
|
collapse: 'Zwiń',
|
||||||
collections: 'Kolekcje',
|
collections: 'Kolekcje',
|
||||||
@@ -414,14 +414,14 @@ export const plTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Ostatnio zapisane {{distance}} temu',
|
lastSavedAgo: 'Ostatnio zapisane {{distance}} temu',
|
||||||
noFurtherVersionsFound: 'Nie znaleziono dalszych wersji',
|
noFurtherVersionsFound: 'Nie znaleziono dalszych wersji',
|
||||||
noRowsFound: 'Nie znaleziono {{label}}',
|
noRowsFound: 'Nie znaleziono {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nie wybrano {{etykieta}}',
|
||||||
preview: 'Podgląd',
|
preview: 'Podgląd',
|
||||||
previouslyPublished: 'Wcześniej opublikowane',
|
previouslyPublished: 'Wcześniej opublikowane',
|
||||||
problemRestoringVersion: 'Wystąpił problem podczas przywracania tej wersji',
|
problemRestoringVersion: 'Wystąpił problem podczas przywracania tej wersji',
|
||||||
publish: 'Publikuj',
|
publish: 'Publikuj',
|
||||||
publishChanges: 'Opublikuj zmiany',
|
publishChanges: 'Opublikuj zmiany',
|
||||||
published: 'Opublikowano',
|
published: 'Opublikowano',
|
||||||
publishIn: undefined,
|
publishIn: 'Opublikuj w {{locale}}',
|
||||||
publishing: 'Publikacja',
|
publishing: 'Publikacja',
|
||||||
restoreAsDraft: 'Przywróć jako szkic',
|
restoreAsDraft: 'Przywróć jako szkic',
|
||||||
restoredSuccessfully: 'Przywrócono pomyślnie.',
|
restoredSuccessfully: 'Przywrócono pomyślnie.',
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ export const ptTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Cancelar',
|
cancel: 'Cancelar',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Suas alterações não foram salvas. Se você sair agora, essas alterações serão perdidas.',
|
'Suas alterações não foram salvas. Se você sair agora, essas alterações serão perdidas.',
|
||||||
clearAll: undefined,
|
clearAll: 'Limpar Tudo',
|
||||||
close: 'Fechar',
|
close: 'Fechar',
|
||||||
collapse: 'Recolher',
|
collapse: 'Recolher',
|
||||||
collections: 'Coleções',
|
collections: 'Coleções',
|
||||||
@@ -267,7 +267,7 @@ export const ptTranslations: DefaultTranslationsObject = {
|
|||||||
nothingFound: 'Nada encontrado',
|
nothingFound: 'Nada encontrado',
|
||||||
noValue: 'Nenhum valor',
|
noValue: 'Nenhum valor',
|
||||||
of: 'de',
|
of: 'de',
|
||||||
only: undefined,
|
only: 'Apenas',
|
||||||
open: 'Abrir',
|
open: 'Abrir',
|
||||||
or: 'Ou',
|
or: 'Ou',
|
||||||
order: 'Ordem',
|
order: 'Ordem',
|
||||||
@@ -415,14 +415,14 @@ export const ptTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Última gravação há {{distance}}',
|
lastSavedAgo: 'Última gravação há {{distance}}',
|
||||||
noFurtherVersionsFound: 'Nenhuma outra versão encontrada',
|
noFurtherVersionsFound: 'Nenhuma outra versão encontrada',
|
||||||
noRowsFound: 'Nenhum(a) {{label}} encontrado(a)',
|
noRowsFound: 'Nenhum(a) {{label}} encontrado(a)',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nenhum {{rótulo}} selecionado',
|
||||||
preview: 'Pré-visualização',
|
preview: 'Pré-visualização',
|
||||||
previouslyPublished: 'Publicado Anteriormente',
|
previouslyPublished: 'Publicado Anteriormente',
|
||||||
problemRestoringVersion: 'Ocorreu um problema ao restaurar essa versão',
|
problemRestoringVersion: 'Ocorreu um problema ao restaurar essa versão',
|
||||||
publish: 'Publicar',
|
publish: 'Publicar',
|
||||||
publishChanges: 'Publicar alterações',
|
publishChanges: 'Publicar alterações',
|
||||||
published: 'Publicado',
|
published: 'Publicado',
|
||||||
publishIn: undefined,
|
publishIn: 'Publicar em {{locale}}',
|
||||||
publishing: 'Publicação',
|
publishing: 'Publicação',
|
||||||
restoreAsDraft: 'Restaurar como rascunho',
|
restoreAsDraft: 'Restaurar como rascunho',
|
||||||
restoredSuccessfully: 'Restaurado com sucesso.',
|
restoredSuccessfully: 'Restaurado com sucesso.',
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ export const roTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Anulați',
|
cancel: 'Anulați',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Modificările dvs. nu au fost salvate. Dacă plecați acum, vă veți pierde modificările.',
|
'Modificările dvs. nu au fost salvate. Dacă plecați acum, vă veți pierde modificările.',
|
||||||
clearAll: undefined,
|
clearAll: 'Șterge tot',
|
||||||
close: 'Închide',
|
close: 'Închide',
|
||||||
collapse: 'Colaps',
|
collapse: 'Colaps',
|
||||||
collections: 'Colecții',
|
collections: 'Colecții',
|
||||||
@@ -422,7 +422,7 @@ export const roTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Ultima salvare acum {{distance}}',
|
lastSavedAgo: 'Ultima salvare acum {{distance}}',
|
||||||
noFurtherVersionsFound: 'Nu s-au găsit alte versiuni',
|
noFurtherVersionsFound: 'Nu s-au găsit alte versiuni',
|
||||||
noRowsFound: 'Nu s-a găsit niciun {{label}}',
|
noRowsFound: 'Nu s-a găsit niciun {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Niciun {{etichetă}} selectat',
|
||||||
preview: 'Previzualizare',
|
preview: 'Previzualizare',
|
||||||
previouslyPublished: 'Publicat anterior',
|
previouslyPublished: 'Publicat anterior',
|
||||||
problemRestoringVersion: 'A existat o problemă la restaurarea acestei versiuni',
|
problemRestoringVersion: 'A existat o problemă la restaurarea acestei versiuni',
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export const rsTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'Назад на контролни панел',
|
backToDashboard: 'Назад на контролни панел',
|
||||||
cancel: 'Откажи',
|
cancel: 'Откажи',
|
||||||
changesNotSaved: 'Ваше промене нису сачуване. Ако изађете сада, изгубићете промене.',
|
changesNotSaved: 'Ваше промене нису сачуване. Ако изађете сада, изгубићете промене.',
|
||||||
clearAll: undefined,
|
clearAll: 'Obriši sve',
|
||||||
close: 'Затвори',
|
close: 'Затвори',
|
||||||
collapse: 'Скупи',
|
collapse: 'Скупи',
|
||||||
collections: 'Колекције',
|
collections: 'Колекције',
|
||||||
@@ -265,7 +265,7 @@ export const rsTranslations: DefaultTranslationsObject = {
|
|||||||
nothingFound: 'Ништа није пронађено',
|
nothingFound: 'Ништа није пронађено',
|
||||||
noValue: 'Без вредности',
|
noValue: 'Без вредности',
|
||||||
of: 'Од',
|
of: 'Од',
|
||||||
only: undefined,
|
only: 'Samo',
|
||||||
open: 'Отвори',
|
open: 'Отвори',
|
||||||
or: 'Или',
|
or: 'Или',
|
||||||
order: 'Редослед',
|
order: 'Редослед',
|
||||||
@@ -409,14 +409,14 @@ export const rsTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Задњи пут сачувано пре {{distance}',
|
lastSavedAgo: 'Задњи пут сачувано пре {{distance}',
|
||||||
noFurtherVersionsFound: 'Нису пронађене наредне верзије',
|
noFurtherVersionsFound: 'Нису пронађене наредне верзије',
|
||||||
noRowsFound: '{{label}} није пронађено',
|
noRowsFound: '{{label}} није пронађено',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nije odabrana {{label}}',
|
||||||
preview: 'Преглед',
|
preview: 'Преглед',
|
||||||
previouslyPublished: 'Prethodno objavljeno',
|
previouslyPublished: 'Prethodno objavljeno',
|
||||||
problemRestoringVersion: 'Настао је проблем при враћању ове верзије',
|
problemRestoringVersion: 'Настао је проблем при враћању ове верзије',
|
||||||
publish: 'Објавити',
|
publish: 'Објавити',
|
||||||
publishChanges: 'Објави промене',
|
publishChanges: 'Објави промене',
|
||||||
published: 'Објављено',
|
published: 'Објављено',
|
||||||
publishIn: undefined,
|
publishIn: 'Objavi na {{locale}}',
|
||||||
publishing: 'Objavljivanje',
|
publishing: 'Objavljivanje',
|
||||||
restoreAsDraft: 'Vrati kao nacrt',
|
restoreAsDraft: 'Vrati kao nacrt',
|
||||||
restoredSuccessfully: 'Успешно враћено.',
|
restoredSuccessfully: 'Успешно враћено.',
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'Nazad na kontrolni panel',
|
backToDashboard: 'Nazad na kontrolni panel',
|
||||||
cancel: 'Otkaži',
|
cancel: 'Otkaži',
|
||||||
changesNotSaved: 'Vaše promene nisu sačuvane. Ako izađete sada, izgubićete promene.',
|
changesNotSaved: 'Vaše promene nisu sačuvane. Ako izađete sada, izgubićete promene.',
|
||||||
clearAll: undefined,
|
clearAll: 'Očisti sve',
|
||||||
close: 'Zatvori',
|
close: 'Zatvori',
|
||||||
collapse: 'Skupi',
|
collapse: 'Skupi',
|
||||||
collections: 'Kolekcije',
|
collections: 'Kolekcije',
|
||||||
@@ -265,7 +265,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
|
|||||||
nothingFound: 'Ništa nije pronađeno',
|
nothingFound: 'Ništa nije pronađeno',
|
||||||
noValue: 'Bez vrednosti',
|
noValue: 'Bez vrednosti',
|
||||||
of: 'Od',
|
of: 'Od',
|
||||||
only: undefined,
|
only: 'Samo',
|
||||||
open: 'Otvori',
|
open: 'Otvori',
|
||||||
or: 'Ili',
|
or: 'Ili',
|
||||||
order: 'Redosled',
|
order: 'Redosled',
|
||||||
@@ -410,7 +410,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Zadnji put sačuvano pre {{distance}',
|
lastSavedAgo: 'Zadnji put sačuvano pre {{distance}',
|
||||||
noFurtherVersionsFound: 'Nisu pronađene naredne verzije',
|
noFurtherVersionsFound: 'Nisu pronađene naredne verzije',
|
||||||
noRowsFound: '{{label}} nije pronađeno',
|
noRowsFound: '{{label}} nije pronađeno',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nije odabrana {{label}}',
|
||||||
preview: 'Pregled',
|
preview: 'Pregled',
|
||||||
previouslyPublished: 'Prethodno objavljeno',
|
previouslyPublished: 'Prethodno objavljeno',
|
||||||
problemRestoringVersion: 'Nastao je problem pri vraćanju ove verzije',
|
problemRestoringVersion: 'Nastao je problem pri vraćanju ove verzije',
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ export const ruTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Отмена',
|
cancel: 'Отмена',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Ваши изменения не были сохранены. Если вы сейчас уйдете, то потеряете свои изменения.',
|
'Ваши изменения не были сохранены. Если вы сейчас уйдете, то потеряете свои изменения.',
|
||||||
clearAll: undefined,
|
clearAll: 'Очистить все',
|
||||||
close: 'Закрыть',
|
close: 'Закрыть',
|
||||||
collapse: 'Свернуть',
|
collapse: 'Свернуть',
|
||||||
collections: 'Коллекции',
|
collections: 'Коллекции',
|
||||||
@@ -416,7 +416,7 @@ export const ruTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Последний раз сохранено {{distance}} назад',
|
lastSavedAgo: 'Последний раз сохранено {{distance}} назад',
|
||||||
noFurtherVersionsFound: 'Другие версии не найдены',
|
noFurtherVersionsFound: 'Другие версии не найдены',
|
||||||
noRowsFound: 'Не найдено {{label}}',
|
noRowsFound: 'Не найдено {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Не выбран {{label}}',
|
||||||
preview: 'Предпросмотр',
|
preview: 'Предпросмотр',
|
||||||
previouslyPublished: 'Ранее опубликовано',
|
previouslyPublished: 'Ранее опубликовано',
|
||||||
problemRestoringVersion: 'Возникла проблема с восстановлением этой версии',
|
problemRestoringVersion: 'Возникла проблема с восстановлением этой версии',
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ export const skTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'Späť na nástenku',
|
backToDashboard: 'Späť na nástenku',
|
||||||
cancel: 'Zrušiť',
|
cancel: 'Zrušiť',
|
||||||
changesNotSaved: 'Vaše zmeny neboli uložené. Ak teraz odídete, stratíte svoje zmeny.',
|
changesNotSaved: 'Vaše zmeny neboli uložené. Ak teraz odídete, stratíte svoje zmeny.',
|
||||||
clearAll: undefined,
|
clearAll: 'Vymazať všetko',
|
||||||
close: 'Zavrieť',
|
close: 'Zavrieť',
|
||||||
collapse: 'Zbaliť',
|
collapse: 'Zbaliť',
|
||||||
collections: 'Kolekcia',
|
collections: 'Kolekcia',
|
||||||
@@ -267,7 +267,7 @@ export const skTranslations: DefaultTranslationsObject = {
|
|||||||
nothingFound: 'Nič nenájdené',
|
nothingFound: 'Nič nenájdené',
|
||||||
noValue: 'Žiadna hodnota',
|
noValue: 'Žiadna hodnota',
|
||||||
of: 'z',
|
of: 'z',
|
||||||
only: undefined,
|
only: 'Iba',
|
||||||
open: 'Otvoriť',
|
open: 'Otvoriť',
|
||||||
or: 'Alebo',
|
or: 'Alebo',
|
||||||
order: 'Poradie',
|
order: 'Poradie',
|
||||||
@@ -414,7 +414,7 @@ export const skTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Naposledy uložené pred {{distance}}',
|
lastSavedAgo: 'Naposledy uložené pred {{distance}}',
|
||||||
noFurtherVersionsFound: 'Nenájdené ďalšie verzie',
|
noFurtherVersionsFound: 'Nenájdené ďalšie verzie',
|
||||||
noRowsFound: 'Nenájdené {{label}}',
|
noRowsFound: 'Nenájdené {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Nie je vybraté žiadne {{označenie}}',
|
||||||
preview: 'Náhľad',
|
preview: 'Náhľad',
|
||||||
previouslyPublished: 'Predtým publikované',
|
previouslyPublished: 'Predtým publikované',
|
||||||
problemRestoringVersion: 'Pri obnovovaní tejto verzie došlo k problému',
|
problemRestoringVersion: 'Pri obnovovaní tejto verzie došlo k problému',
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export const svTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'Avbryt',
|
cancel: 'Avbryt',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Dina ändringar har inte sparats. Om du lämnar nu kommer du att förlora dina ändringar.',
|
'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',
|
close: 'Stänga',
|
||||||
collapse: 'Kollapsa',
|
collapse: 'Kollapsa',
|
||||||
collections: 'Samlingar',
|
collections: 'Samlingar',
|
||||||
@@ -413,7 +413,7 @@ export const svTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Senast sparad för {{distance}} sedan',
|
lastSavedAgo: 'Senast sparad för {{distance}} sedan',
|
||||||
noFurtherVersionsFound: 'Inga fler versioner hittades',
|
noFurtherVersionsFound: 'Inga fler versioner hittades',
|
||||||
noRowsFound: 'Inga {{label}} hittades',
|
noRowsFound: 'Inga {{label}} hittades',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Inget {{etikett}} valt',
|
||||||
preview: 'Förhandsvisa',
|
preview: 'Förhandsvisa',
|
||||||
previouslyPublished: 'Tidigare publicerad',
|
previouslyPublished: 'Tidigare publicerad',
|
||||||
problemRestoringVersion: 'Det uppstod ett problem när den här versionen skulle återställas',
|
problemRestoringVersion: 'Det uppstod ett problem när den här versionen skulle återställas',
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ export const thTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'กลับไปหน้าแดชบอร์ด',
|
backToDashboard: 'กลับไปหน้าแดชบอร์ด',
|
||||||
cancel: 'ยกเลิก',
|
cancel: 'ยกเลิก',
|
||||||
changesNotSaved: 'การเปลี่ยนแปลงยังไม่ได้ถูกบันทึก ถ้าคุณออกตอนนี้ สิ่งที่แก้ไขไว้จะหายไป',
|
changesNotSaved: 'การเปลี่ยนแปลงยังไม่ได้ถูกบันทึก ถ้าคุณออกตอนนี้ สิ่งที่แก้ไขไว้จะหายไป',
|
||||||
clearAll: undefined,
|
clearAll: 'ล้างทั้งหมด',
|
||||||
close: 'ปิด',
|
close: 'ปิด',
|
||||||
collapse: 'ยุบ',
|
collapse: 'ยุบ',
|
||||||
collections: 'Collections',
|
collections: 'Collections',
|
||||||
@@ -405,7 +405,7 @@ export const thTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'บันทึกครั้งล่าสุด {{distance}} ที่ผ่านมา',
|
lastSavedAgo: 'บันทึกครั้งล่าสุด {{distance}} ที่ผ่านมา',
|
||||||
noFurtherVersionsFound: 'ไม่พบเวอร์ชันอื่น ๆ',
|
noFurtherVersionsFound: 'ไม่พบเวอร์ชันอื่น ๆ',
|
||||||
noRowsFound: 'ไม่พบ {{label}}',
|
noRowsFound: 'ไม่พบ {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'ไม่มี {{label}} ที่ถูกเลือก',
|
||||||
preview: 'ตัวอย่าง',
|
preview: 'ตัวอย่าง',
|
||||||
previouslyPublished: 'เผยแพร่ก่อนหน้านี้',
|
previouslyPublished: 'เผยแพร่ก่อนหน้านี้',
|
||||||
problemRestoringVersion: 'เกิดปัญหาระหว่างการกู้คืนเวอร์ชันนี้',
|
problemRestoringVersion: 'เกิดปัญหาระหว่างการกู้คืนเวอร์ชันนี้',
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ export const trTranslations: DefaultTranslationsObject = {
|
|||||||
cancel: 'İptal',
|
cancel: 'İptal',
|
||||||
changesNotSaved:
|
changesNotSaved:
|
||||||
'Değişiklikleriniz henüz kaydedilmedi. Eğer bu sayfayı terk ederseniz değişiklikleri kaybedeceksiniz.',
|
'Değişiklikleriniz henüz kaydedilmedi. Eğer bu sayfayı terk ederseniz değişiklikleri kaybedeceksiniz.',
|
||||||
clearAll: undefined,
|
clearAll: 'Hepsini Temizle',
|
||||||
close: 'Kapat',
|
close: 'Kapat',
|
||||||
collapse: 'Daralt',
|
collapse: 'Daralt',
|
||||||
collections: 'Koleksiyonlar',
|
collections: 'Koleksiyonlar',
|
||||||
@@ -415,7 +415,7 @@ export const trTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Son kaydedildi {{distance}} önce',
|
lastSavedAgo: 'Son kaydedildi {{distance}} önce',
|
||||||
noFurtherVersionsFound: 'Başka sürüm bulunamadı.',
|
noFurtherVersionsFound: 'Başka sürüm bulunamadı.',
|
||||||
noRowsFound: '{{label}} bulunamadı',
|
noRowsFound: '{{label}} bulunamadı',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Seçilen {{label}} yok',
|
||||||
preview: 'Önizleme',
|
preview: 'Önizleme',
|
||||||
previouslyPublished: 'Daha Önce Yayınlanmış',
|
previouslyPublished: 'Daha Önce Yayınlanmış',
|
||||||
problemRestoringVersion: 'Bu sürüme geri döndürürken bir hatayla karşılaşıldı.',
|
problemRestoringVersion: 'Bu sürüme geri döndürürken bir hatayla karşılaşıldı.',
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export const ukTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'Повернутись до головної сторінки',
|
backToDashboard: 'Повернутись до головної сторінки',
|
||||||
cancel: 'Скасувати',
|
cancel: 'Скасувати',
|
||||||
changesNotSaved: 'Ваши зміни не були збережені. Якщо ви вийдете зараз, то втратите свої зміни.',
|
changesNotSaved: 'Ваши зміни не були збережені. Якщо ви вийдете зараз, то втратите свої зміни.',
|
||||||
clearAll: undefined,
|
clearAll: 'Очистити все',
|
||||||
close: 'Закрити',
|
close: 'Закрити',
|
||||||
collapse: 'Згорнути',
|
collapse: 'Згорнути',
|
||||||
collections: 'Колекції',
|
collections: 'Колекції',
|
||||||
@@ -413,7 +413,7 @@ export const ukTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Востаннє збережено {{distance}} тому',
|
lastSavedAgo: 'Востаннє збережено {{distance}} тому',
|
||||||
noFurtherVersionsFound: 'Інших версій не знайдено',
|
noFurtherVersionsFound: 'Інших версій не знайдено',
|
||||||
noRowsFound: 'Не знайдено {{label}}',
|
noRowsFound: 'Не знайдено {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Не вибрано {{label}}',
|
||||||
preview: 'Попередній перегляд',
|
preview: 'Попередній перегляд',
|
||||||
previouslyPublished: 'Раніше опубліковано',
|
previouslyPublished: 'Раніше опубліковано',
|
||||||
problemRestoringVersion: 'Виникла проблема з відновленням цієї версії',
|
problemRestoringVersion: 'Виникла проблема з відновленням цієї версії',
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ export const viTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: 'Quay lại bảng điều khiển',
|
backToDashboard: 'Quay lại bảng điều khiển',
|
||||||
cancel: 'Hủy',
|
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ờ.',
|
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',
|
close: 'Gần',
|
||||||
collapse: 'Thu gọn',
|
collapse: 'Thu gọn',
|
||||||
collections: 'Collections',
|
collections: 'Collections',
|
||||||
@@ -264,7 +264,7 @@ export const viTranslations: DefaultTranslationsObject = {
|
|||||||
nothingFound: 'Không tìm thấy',
|
nothingFound: 'Không tìm thấy',
|
||||||
noValue: 'Không có giá trị',
|
noValue: 'Không có giá trị',
|
||||||
of: 'trong số',
|
of: 'trong số',
|
||||||
only: undefined,
|
only: 'Chỉ',
|
||||||
open: 'Mở',
|
open: 'Mở',
|
||||||
or: 'hoặc',
|
or: 'hoặc',
|
||||||
order: 'Thứ tự',
|
order: 'Thứ tự',
|
||||||
@@ -408,7 +408,7 @@ export const viTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: 'Lần lưu cuối cùng {{distance}} trước đây',
|
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',
|
noFurtherVersionsFound: 'Không tìm thấy phiên bản cũ hơn',
|
||||||
noRowsFound: 'Không tìm thấy: {{label}}',
|
noRowsFound: 'Không tìm thấy: {{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: 'Không có {{label}} được chọn',
|
||||||
preview: 'Bản xem trước',
|
preview: 'Bản xem trước',
|
||||||
previouslyPublished: 'Đã xuất bản trước đây',
|
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',
|
problemRestoringVersion: 'Đã xảy ra vấn đề khi khôi phục phiên bản này',
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ export const zhTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: '返回到仪表板',
|
backToDashboard: '返回到仪表板',
|
||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
changesNotSaved: '您的更改尚未保存。您确定要离开吗?',
|
changesNotSaved: '您的更改尚未保存。您确定要离开吗?',
|
||||||
clearAll: undefined,
|
clearAll: '清除全部',
|
||||||
close: '关闭',
|
close: '关闭',
|
||||||
collapse: '折叠',
|
collapse: '折叠',
|
||||||
collections: '集合',
|
collections: '集合',
|
||||||
@@ -258,7 +258,7 @@ export const zhTranslations: DefaultTranslationsObject = {
|
|||||||
nothingFound: '没有找到任何东西',
|
nothingFound: '没有找到任何东西',
|
||||||
noValue: '没有值',
|
noValue: '没有值',
|
||||||
of: '的',
|
of: '的',
|
||||||
only: undefined,
|
only: '仅',
|
||||||
open: '打开',
|
open: '打开',
|
||||||
or: '或',
|
or: '或',
|
||||||
order: '排序',
|
order: '排序',
|
||||||
@@ -398,14 +398,14 @@ export const zhTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: '上次保存{{distance}}之前',
|
lastSavedAgo: '上次保存{{distance}}之前',
|
||||||
noFurtherVersionsFound: '没有发现其他版本',
|
noFurtherVersionsFound: '没有发现其他版本',
|
||||||
noRowsFound: '没有发现{{label}}',
|
noRowsFound: '没有发现{{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: '未选择{{label}}',
|
||||||
preview: '预览',
|
preview: '预览',
|
||||||
previouslyPublished: '先前发布过的',
|
previouslyPublished: '先前发布过的',
|
||||||
problemRestoringVersion: '恢复这个版本时发生了问题',
|
problemRestoringVersion: '恢复这个版本时发生了问题',
|
||||||
publish: '发布',
|
publish: '发布',
|
||||||
publishChanges: '发布修改',
|
publishChanges: '发布修改',
|
||||||
published: '已发布',
|
published: '已发布',
|
||||||
publishIn: undefined,
|
publishIn: '在{{locale}}发布',
|
||||||
publishing: '发布',
|
publishing: '发布',
|
||||||
restoreAsDraft: '恢复为草稿',
|
restoreAsDraft: '恢复为草稿',
|
||||||
restoredSuccessfully: '恢复成功。',
|
restoredSuccessfully: '恢复成功。',
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ export const zhTwTranslations: DefaultTranslationsObject = {
|
|||||||
backToDashboard: '返回到控制面板',
|
backToDashboard: '返回到控制面板',
|
||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
changesNotSaved: '您還有尚未儲存的變更。您確定要離開嗎?',
|
changesNotSaved: '您還有尚未儲存的變更。您確定要離開嗎?',
|
||||||
clearAll: undefined,
|
clearAll: '清除全部',
|
||||||
close: '關閉',
|
close: '關閉',
|
||||||
collapse: '折疊',
|
collapse: '折疊',
|
||||||
collections: '集合',
|
collections: '集合',
|
||||||
@@ -398,14 +398,14 @@ export const zhTwTranslations: DefaultTranslationsObject = {
|
|||||||
lastSavedAgo: '上次儲存在{{distance}}之前',
|
lastSavedAgo: '上次儲存在{{distance}}之前',
|
||||||
noFurtherVersionsFound: '沒有發現其他版本',
|
noFurtherVersionsFound: '沒有發現其他版本',
|
||||||
noRowsFound: '沒有發現{{label}}',
|
noRowsFound: '沒有發現{{label}}',
|
||||||
noRowsSelected: undefined,
|
noRowsSelected: '未選擇 {{label}}',
|
||||||
preview: '預覽',
|
preview: '預覽',
|
||||||
previouslyPublished: '先前出版過的',
|
previouslyPublished: '先前出版過的',
|
||||||
problemRestoringVersion: '回復這個版本時發生了問題',
|
problemRestoringVersion: '回復這個版本時發生了問題',
|
||||||
publish: '發佈',
|
publish: '發佈',
|
||||||
publishChanges: '發佈修改',
|
publishChanges: '發佈修改',
|
||||||
published: '已發佈',
|
published: '已發佈',
|
||||||
publishIn: undefined,
|
publishIn: '在 {{locale}} 發佈',
|
||||||
publishing: '發布',
|
publishing: '發布',
|
||||||
restoreAsDraft: '恢復為草稿',
|
restoreAsDraft: '恢復為草稿',
|
||||||
restoredSuccessfully: '回復成功。',
|
restoredSuccessfully: '回復成功。',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { ClientUser, MeOperationResult, Permissions } from 'payload'
|
import type { ClientUser, MeOperationResult, Permissions, User } from 'payload'
|
||||||
|
|
||||||
import { useModal } from '@faceless-ui/modal'
|
import { useModal } from '@faceless-ui/modal'
|
||||||
import { usePathname, useRouter } from 'next/navigation.js'
|
import { usePathname, useRouter } from 'next/navigation.js'
|
||||||
@@ -15,7 +15,7 @@ import { formatAdminURL } from '../../utilities/formatAdminURL.js'
|
|||||||
import { useConfig } from '../Config/index.js'
|
import { useConfig } from '../Config/index.js'
|
||||||
|
|
||||||
export type AuthContext<T = ClientUser> = {
|
export type AuthContext<T = ClientUser> = {
|
||||||
fetchFullUser: () => Promise<void>
|
fetchFullUser: () => Promise<null | User>
|
||||||
logOut: () => Promise<void>
|
logOut: () => Promise<void>
|
||||||
permissions?: Permissions
|
permissions?: Permissions
|
||||||
refreshCookie: (forceRefresh?: boolean) => void
|
refreshCookie: (forceRefresh?: boolean) => void
|
||||||
@@ -227,6 +227,7 @@ export function AuthProvider({
|
|||||||
const fetchFullUser = React.useCallback(async () => {
|
const fetchFullUser = React.useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const request = await requests.get(`${serverURL}${apiRoute}/${userSlug}/me`, {
|
const request = await requests.get(`${serverURL}${apiRoute}/${userSlug}/me`, {
|
||||||
|
credentials: 'include',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept-Language': i18n.language,
|
'Accept-Language': i18n.language,
|
||||||
},
|
},
|
||||||
@@ -234,9 +235,11 @@ export function AuthProvider({
|
|||||||
|
|
||||||
if (request.status === 200) {
|
if (request.status === 200) {
|
||||||
const json: MeOperationResult = await request.json()
|
const json: MeOperationResult = await request.json()
|
||||||
|
let user = null
|
||||||
|
|
||||||
if (json?.user) {
|
if (json?.user) {
|
||||||
setUser(json.user)
|
setUser(json.user)
|
||||||
|
user = json.user
|
||||||
|
|
||||||
if (json?.token) {
|
if (json?.token) {
|
||||||
setTokenAndExpiration(json)
|
setTokenAndExpiration(json)
|
||||||
@@ -245,10 +248,14 @@ export function AuthProvider({
|
|||||||
setUser(null)
|
setUser(null)
|
||||||
revokeTokenAndExpire()
|
revokeTokenAndExpire()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return user
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.error(`Fetching user failed: ${e.message}`)
|
toast.error(`Fetching user failed: ${e.message}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
}, [serverURL, apiRoute, userSlug, i18n.language, setTokenAndExpiration, revokeTokenAndExpire])
|
}, [serverURL, apiRoute, userSlug, i18n.language, setTokenAndExpiration, revokeTokenAndExpire])
|
||||||
|
|
||||||
// On mount, get user and set
|
// On mount, get user and set
|
||||||
|
|||||||
@@ -482,7 +482,7 @@ describe('access control', () => {
|
|||||||
serverURL,
|
serverURL,
|
||||||
})
|
})
|
||||||
|
|
||||||
await expect(page.locator('.next-error-h1')).toBeVisible()
|
await expect(page.locator('.unauthorized')).toBeVisible()
|
||||||
|
|
||||||
await page.goto(logoutURL)
|
await page.goto(logoutURL)
|
||||||
await page.waitForURL(logoutURL)
|
await page.waitForURL(logoutURL)
|
||||||
@@ -500,6 +500,7 @@ describe('access control', () => {
|
|||||||
|
|
||||||
test('should block admin access to non-admin user', async () => {
|
test('should block admin access to non-admin user', async () => {
|
||||||
const adminURL = `${serverURL}/admin`
|
const adminURL = `${serverURL}/admin`
|
||||||
|
const unauthorizedURL = `${serverURL}/admin/unauthorized`
|
||||||
await page.goto(adminURL)
|
await page.goto(adminURL)
|
||||||
await page.waitForURL(adminURL)
|
await page.waitForURL(adminURL)
|
||||||
|
|
||||||
@@ -527,9 +528,9 @@ describe('access control', () => {
|
|||||||
])
|
])
|
||||||
|
|
||||||
await page.goto(adminURL)
|
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()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -310,6 +310,7 @@ export function initPageConsoleErrorCatch(page: Page) {
|
|||||||
!msg.text().includes('the server responded with a status of') &&
|
!msg.text().includes('the server responded with a status of') &&
|
||||||
!msg.text().includes('Failed to fetch RSC payload for') &&
|
!msg.text().includes('Failed to fetch RSC payload for') &&
|
||||||
!msg.text().includes('Error: NEXT_NOT_FOUND') &&
|
!msg.text().includes('Error: NEXT_NOT_FOUND') &&
|
||||||
|
!msg.text().includes('Error: NEXT_REDIRECT') &&
|
||||||
!msg.text().includes('Error getting document data')
|
!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
|
// "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
|
||||||
|
|||||||
Reference in New Issue
Block a user