feat(webapp-access): add WEBAPP_PUBLIC_ACCESS_ENABLED toggle (#38567)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Xiyuan Chen 2026-07-21 01:46:28 -07:00 committed by GitHub
parent ed1289281d
commit 62bbc0dbeb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 268 additions and 9 deletions

View File

@ -14,6 +14,12 @@ class EnterpriseFeatureConfig(BaseSettings):
default=False,
)
WEBAPP_PUBLIC_ACCESS_ENABLED: bool = Field(
description="Whether admins are allowed to set a webapp's access mode to public (anyone with the link, "
"no auth). Disable in security-sensitive on-prem deployments.",
default=True,
)
CAN_REPLACE_LOGO: bool = Field(
description="Allow customization of the enterprise logo.",
default=False,

View File

@ -22940,6 +22940,7 @@ in form definiton, or a variable while the workflow is running.
| ---- | ---- | ----------- | -------- |
| allow_email_code_login | boolean | | Yes |
| allow_email_password_login | boolean | | Yes |
| allow_public_access | boolean, <br>**Default:** true | | Yes |
| allow_sso | boolean | | Yes |
| enabled | boolean | | Yes |
| sso_config | [WebAppAuthSSOModel](#webappauthssomodel) | | Yes |

View File

@ -1643,6 +1643,7 @@ in form definiton, or a variable while the workflow is running.
| ---- | ---- | ----------- | -------- |
| allow_email_code_login | boolean | | Yes |
| allow_email_password_login | boolean | | Yes |
| allow_public_access | boolean, <br>**Default:** true | | Yes |
| allow_sso | boolean | | Yes |
| enabled | boolean | | Yes |
| sso_config | [WebAppAuthSSOModel](#webappauthssomodel) | | Yes |

View File

@ -100,6 +100,7 @@ class WebAppAuthModel(FeatureResponseModel):
sso_config: WebAppAuthSSOModel = WebAppAuthSSOModel()
allow_email_code_login: bool = False
allow_email_password_login: bool = False
allow_public_access: bool = True
class KnowledgePipeline(FeatureResponseModel):
@ -286,6 +287,7 @@ class FeatureService:
system_features.enable_trial_app = dify_config.ENABLE_TRIAL_APP
system_features.enable_explore_banner = dify_config.ENABLE_EXPLORE_BANNER
system_features.enable_learn_app = dify_config.ENABLE_LEARN_APP
system_features.webapp_auth.allow_public_access = dify_config.WEBAPP_PUBLIC_ACCESS_ENABLED
system_features.enable_step_by_step_tour = dify_config.ENABLE_STEP_BY_STEP_TOUR
@classmethod

View File

@ -0,0 +1,30 @@
import pytest
from services.feature_service import FeatureService, SystemFeatureModel
@pytest.mark.parametrize(
("env_value", "expected"),
[
(False, False),
(True, True),
],
ids=["disabled_by_env", "enabled_by_env"],
)
def test_fulfill_system_params_from_env_sets_allow_public_access(
monkeypatch: pytest.MonkeyPatch,
env_value: bool,
expected: bool,
):
monkeypatch.setattr("services.feature_service.dify_config.WEBAPP_PUBLIC_ACCESS_ENABLED", env_value)
system_features = SystemFeatureModel()
FeatureService._fulfill_system_params_from_env(system_features)
assert system_features.webapp_auth.allow_public_access is expected
def test_get_system_features_defaults_allow_public_access_to_true():
system_features = FeatureService.get_system_features()
assert system_features.webapp_auth.allow_public_access is True

View File

@ -58,6 +58,7 @@ export type PluginManagerModel = {
export type WebAppAuthModel = {
allow_email_code_login: boolean
allow_email_password_login: boolean
allow_public_access: boolean
allow_sso: boolean
enabled: boolean
sso_config: WebAppAuthSsoModel

View File

@ -87,6 +87,7 @@ export const zWebAppAuthSsoModel = z.object({
export const zWebAppAuthModel = z.object({
allow_email_code_login: z.boolean().default(false),
allow_email_password_login: z.boolean().default(false),
allow_public_access: z.boolean().default(true),
allow_sso: z.boolean().default(false),
enabled: z.boolean().default(false),
sso_config: zWebAppAuthSsoModel.default({ protocol: '' }),
@ -144,6 +145,7 @@ export const zSystemFeatureModel = z.object({
webapp_auth: zWebAppAuthModel.default({
allow_email_code_login: false,
allow_email_password_login: false,
allow_public_access: true,
allow_sso: false,
enabled: false,
sso_config: { protocol: '' },

View File

@ -567,6 +567,7 @@ export type VerificationTokenResponse = {
export type WebAppAuthModel = {
allow_email_code_login: boolean
allow_email_password_login: boolean
allow_public_access: boolean
allow_sso: boolean
enabled: boolean
sso_config: WebAppAuthSsoModel

View File

@ -765,6 +765,7 @@ export const zWebAppAuthSsoModel = z.object({
export const zWebAppAuthModel = z.object({
allow_email_code_login: z.boolean().default(false),
allow_email_password_login: z.boolean().default(false),
allow_public_access: z.boolean().default(true),
allow_sso: z.boolean().default(false),
enabled: z.boolean().default(false),
sso_config: zWebAppAuthSsoModel.default({ protocol: '' }),
@ -822,6 +823,7 @@ export const zSystemFeatureModel = z.object({
webapp_auth: zWebAppAuthModel.default({
allow_email_code_login: false,
allow_email_password_login: false,
allow_public_access: true,
allow_sso: false,
enabled: false,
sso_config: { protocol: '' },

View File

@ -47,4 +47,25 @@ describe('AccessControlItem', () => {
expect(anyone).toBeChecked()
})
it('should not select a disabled option', async () => {
const user = userEvent.setup()
render(
<RadioGroup<AccessMode> aria-label="Access" defaultValue={AccessMode.PUBLIC}>
<AccessControlItem type={AccessMode.ORGANIZATION} disabled>
Organization Only
</AccessControlItem>
<AccessControlItem type={AccessMode.PUBLIC}>Anyone</AccessControlItem>
</RadioGroup>,
)
const organization = screen.getByRole('radio', { name: 'Organization Only' })
expect(organization).toHaveAttribute('aria-disabled', 'true')
expect(organization).toHaveClass('cursor-not-allowed')
await user.click(organization)
expect(organization).not.toBeChecked()
expect(screen.getByRole('radio', { name: 'Anyone' })).toBeChecked()
})
})

View File

@ -13,6 +13,7 @@ let mockWebappAuth = {
allow_sso: true,
allow_email_password_login: false,
allow_email_code_login: false,
allow_public_access: true,
}
const render = (ui: ReactElement) =>
@ -53,6 +54,7 @@ describe('AccessControl', () => {
allow_sso: true,
allow_email_password_login: false,
allow_email_code_login: false,
allow_public_access: true,
}
useAccessControlStore.setState({
appId: '',
@ -113,6 +115,7 @@ describe('AccessControl', () => {
allow_sso: false,
allow_email_password_login: false,
allow_email_code_login: false,
allow_public_access: true,
}
render(
@ -141,4 +144,48 @@ describe('AccessControl', () => {
expect(organization).toBeChecked()
})
describe('public access control', () => {
it('should render the public option enabled without a tooltip when public access is allowed', () => {
render(
<AccessControl
app={{ id: 'app-id-4', access_mode: AccessMode.SPECIFIC_GROUPS_MEMBERS } as App}
onClose={vi.fn()}
/>,
)
const publicOption = screen.getByRole('radio', {
name: /app\.accessControlDialog\.accessItems\.anyone/,
})
expect(publicOption).not.toHaveAttribute('data-disabled')
expect(
screen.queryByLabelText('app.accessControlDialog.webAppPublicAccessDisabledTip'),
).not.toBeInTheDocument()
})
it('should render the public option disabled with a tooltip when public access is disabled', () => {
mockWebappAuth = {
enabled: true,
allow_sso: true,
allow_email_password_login: false,
allow_email_code_login: false,
allow_public_access: false,
}
render(
<AccessControl
app={{ id: 'app-id-5', access_mode: AccessMode.SPECIFIC_GROUPS_MEMBERS } as App}
onClose={vi.fn()}
/>,
)
const publicOption = screen.getByRole('radio', {
name: /app\.accessControlDialog\.accessItems\.anyone/,
})
expect(publicOption).toHaveAttribute('aria-disabled', 'true')
expect(
screen.getByLabelText('app.accessControlDialog.webAppPublicAccessDisabledTip'),
).toBeInTheDocument()
})
})
})

View File

@ -6,18 +6,22 @@ import { RadioItem } from '@langgenius/dify-ui/radio'
type AccessControlItemProps = PropsWithChildren<{
type: AccessMode
disabled?: boolean
}>
export default function AccessControlItem({ type, children }: AccessControlItemProps) {
export default function AccessControlItem({ type, children, disabled }: AccessControlItemProps) {
return (
<RadioItem<AccessMode>
value={type}
disabled={disabled}
render={<div />}
className={cn(
'cursor-pointer rounded-[10px] border-[0.5px] border-components-option-card-option-border bg-components-option-card-option-bg shadow-xs transition-colors',
'hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover',
'rounded-[10px] border-[0.5px] border-components-option-card-option-border bg-components-option-card-option-bg shadow-xs transition-colors',
'focus-visible:ring-2 focus-visible:ring-state-accent-solid focus-visible:outline-hidden',
'data-checked:border-components-option-card-option-selected-border data-checked:bg-components-option-card-option-selected-bg data-checked:inset-ring-[0.5px] data-checked:inset-ring-components-option-card-option-selected-border',
disabled
? 'cursor-not-allowed opacity-60'
: 'cursor-pointer hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover',
)}
>
{children}

View File

@ -13,6 +13,7 @@ import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { AccessMode, SubjectType } from '@/models/access-control'
import { consoleQuery } from '@/service/client'
import useAccessControlStore from '../../../../context/access-control-store'
import { Infotip } from '../../base/infotip'
import AccessControlDialog from './access-control-dialog'
import AccessControlItem from './access-control-item'
import SpecificGroupsOrMembers, { WebAppSSONotEnabledTip } from './specific-groups-or-members'
@ -39,6 +40,7 @@ export default function AccessControl(props: AccessControlProps) {
(systemFeatures.webapp_auth.allow_sso ||
systemFeatures.webapp_auth.allow_email_password_login ||
systemFeatures.webapp_auth.allow_email_code_login)
const publicAccessDisabled = !systemFeatures.webapp_auth.allow_public_access
useEffect(() => {
setAppId(appId)
@ -48,7 +50,9 @@ export default function AccessControl(props: AccessControlProps) {
const { isPending, mutateAsync: updateAccessMode } = useMutation(
consoleQuery.enterprise.webAppAuth.updateWebAppWhitelistSubjects.mutationOptions(),
)
const confirmDisabled = isPending || (currentMenu === AccessMode.PUBLIC && publicAccessDisabled)
const handleConfirm = useCallback(async () => {
if (confirmDisabled) return
const submitData: {
appId: string
accessMode: AccessMode
@ -70,7 +74,16 @@ export default function AccessControl(props: AccessControlProps) {
await updateAccessMode({ body: submitData })
toast.success(t(($) => $['accessControlDialog.updateSuccess'], { ns: 'app' }))
onConfirm?.()
}, [updateAccessMode, appId, specificGroups, specificMembers, t, onConfirm, currentMenu])
}, [
updateAccessMode,
appId,
specificGroups,
specificMembers,
t,
onConfirm,
currentMenu,
confirmDisabled,
])
return (
<AccessControlDialog show onClose={onClose}>
<div className="flex flex-col gap-y-3">
@ -117,19 +130,29 @@ export default function AccessControl(props: AccessControlProps) {
{!hideTip && <WebAppSSONotEnabledTip />}
</div>
</AccessControlItem>
<AccessControlItem type={AccessMode.PUBLIC}>
<AccessControlItem type={AccessMode.PUBLIC} disabled={publicAccessDisabled}>
<div className="flex items-center gap-x-2 p-3">
<RiGlobalLine className="size-4 text-text-primary" />
<p className="system-sm-medium text-text-primary">
{t(($) => $['accessControlDialog.accessItems.anyone'], { ns: 'app' })}
</p>
{publicAccessDisabled && (
<Infotip
aria-label={t(($) => $['accessControlDialog.webAppPublicAccessDisabledTip'], {
ns: 'app',
})}
className="h-4 w-4 shrink-0 text-text-warning-secondary hover:text-text-warning-secondary"
>
{t(($) => $['accessControlDialog.webAppPublicAccessDisabledTip'], { ns: 'app' })}
</Infotip>
)}
</div>
</AccessControlItem>
</RadioGroup>
<div className="flex items-center justify-end gap-x-2 p-6 pt-5">
<Button onClick={onClose}>{t(($) => $['operation.cancel'], { ns: 'common' })}</Button>
<Button
disabled={isPending}
disabled={confirmDisabled}
loading={isPending}
variant="primary"
onClick={handleConfirm}

View File

@ -1,6 +1,8 @@
import type { ReactElement } from 'react'
import { AccessSubjectType } from '@dify/contracts/enterprise/types.gen'
import { fireEvent, render, screen } from '@testing-library/react'
import { fireEvent, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { DeploymentAccessControlDialog } from '../access-control-dialog'
const mockUseSearchAccessSubjects = vi.hoisted(() => vi.fn())
@ -9,6 +11,11 @@ vi.mock('@/service/access-control/use-access-subjects', () => ({
useSearchAccessSubjects: (...args: unknown[]) => mockUseSearchAccessSubjects(...args),
}))
const render = (ui: ReactElement, allowPublicAccess = true) =>
renderWithConsoleQuery(ui, {
systemFeatures: { webapp_auth: { allow_public_access: allowPublicAccess } },
})
describe('DeploymentAccessControlDialog', () => {
beforeEach(() => {
vi.clearAllMocks()
@ -61,4 +68,61 @@ describe('DeploymentAccessControlDialog', () => {
},
])
})
describe('public access control', () => {
it('should allow selecting the public option when public access is allowed', () => {
const handleSubmit = vi.fn()
render(
<DeploymentAccessControlDialog
open
initialKind="organization"
initialSubjects={[]}
onClose={vi.fn()}
onSubmit={handleSubmit}
/>,
true,
)
const publicOption = screen.getByRole('radio', {
name: 'app.accessControlDialog.accessItems.anyone',
})
expect(publicOption).not.toHaveAttribute('data-disabled')
fireEvent.click(publicOption)
fireEvent.click(screen.getByRole('button', { name: 'common.operation.confirm' }))
expect(handleSubmit).toHaveBeenCalledWith('anyone', [])
})
it('should disable the public option and show a tooltip when public access is disabled', () => {
const handleSubmit = vi.fn()
render(
<DeploymentAccessControlDialog
open
initialKind="organization"
initialSubjects={[]}
onClose={vi.fn()}
onSubmit={handleSubmit}
/>,
false,
)
const publicOption = screen.getByRole('radio', {
name: 'app.accessControlDialog.accessItems.anyone',
})
expect(publicOption).toHaveAttribute('data-disabled')
expect(
screen.getByRole('button', {
name: 'app.accessControlDialog.webAppPublicAccessDisabledTip',
}),
).toBeInTheDocument()
fireEvent.click(publicOption)
fireEvent.click(screen.getByRole('button', { name: 'common.operation.confirm' }))
expect(handleSubmit).toHaveBeenCalledWith('organization', [])
})
})
})

View File

@ -45,6 +45,11 @@ vi.mock('@tanstack/react-query', async (importOriginal) => {
isPending: false,
mutate: mockMutate,
}),
useSuspenseQuery: () => ({
data: {
webapp_auth: { allow_public_access: true },
},
}),
}
})
@ -57,6 +62,11 @@ vi.mock('@/service/client', () => ({
},
},
},
systemFeatures: {
get: {
queryKey: () => ['console', 'systemFeatures'],
},
},
},
}))

View File

@ -13,8 +13,11 @@ import {
DialogTitle,
} from '@langgenius/dify-ui/dialog'
import { RadioGroup, RadioItem } from '@langgenius/dify-ui/radio'
import { useSuspenseQuery } from '@tanstack/react-query'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Infotip } from '@/app/components/base/infotip'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { AccessMode as AppAccessMode } from '@/models/access-control'
import {
accessControlSelectionFromSubjects,
@ -82,14 +85,17 @@ function DeploymentAccessControlDialogBody({
onSubmit: (kind: AccessPermissionKind, subjects: SelectableAccessSubject[]) => void
}) {
const { t } = useTranslation('deployments')
const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions())
const [currentMenu, setCurrentMenu] = useState(() => permissionKeyToAppAccessMode(initialKind))
const [specificSelection, setSpecificSelection] = useState<AccessSubjectSelectionValue>(() =>
accessControlSelectionFromSubjects(initialSubjects),
)
const specificSelected = currentMenu === AppAccessMode.SPECIFIC_GROUPS_MEMBERS
const publicAccessDisabled = !systemFeatures.webapp_auth.allow_public_access
const selectedSubjectCount = specificSelection.groups.length + specificSelection.members.length
const specificEmpty = specificSelected && selectedSubjectCount === 0
const confirmDisabled = saving || (specificSelected && specificEmpty)
const publicSelectedDisabled = currentMenu === AppAccessMode.PUBLIC && publicAccessDisabled
const confirmDisabled = saving || (specificSelected && specificEmpty) || publicSelectedDisabled
const handleConfirm = () => {
if (confirmDisabled) return
@ -139,12 +145,22 @@ function DeploymentAccessControlDialogBody({
onSelectionChange={setSpecificSelection}
/>
</AccessControlItem>
<AccessControlItem type={AppAccessMode.PUBLIC}>
<AccessControlItem type={AppAccessMode.PUBLIC} disabled={publicAccessDisabled}>
<div className="flex items-center gap-x-2 p-3">
<span className="i-ri-global-line size-4 text-text-primary" aria-hidden="true" />
<p className="system-sm-medium text-text-primary">
{t(($) => $['accessControlDialog.accessItems.anyone'], { ns: 'app' })}
</p>
{publicAccessDisabled && (
<Infotip
aria-label={t(($) => $['accessControlDialog.webAppPublicAccessDisabledTip'], {
ns: 'app',
})}
className="size-3.5 shrink-0 text-text-warning-secondary hover:text-text-warning-secondary"
>
{t(($) => $['accessControlDialog.webAppPublicAccessDisabledTip'], { ns: 'app' })}
</Infotip>
)}
</div>
</AccessControlItem>
</RadioGroup>
@ -168,12 +184,15 @@ function DeploymentAccessControlDialogBody({
function AccessControlItem({
type,
children,
disabled,
}: PropsWithChildren<{
type: AppAccessMode
disabled?: boolean
}>) {
return (
<RadioItem<AppAccessMode>
value={type}
disabled={disabled}
render={<div />}
className={cn(
'cursor-pointer rounded-[10px] border-[0.5px] border-components-option-card-option-border bg-components-option-card-option-bg shadow-xs transition-colors',

View File

@ -45,6 +45,7 @@ export const defaultSystemFeatures = {
},
allow_email_code_login: false,
allow_email_password_login: false,
allow_public_access: true,
},
plugin_installation_permission: {
plugin_installation_scope: InstallationScope.ALL,
@ -98,6 +99,7 @@ export const cloudSystemFeatures = {
},
allow_email_code_login: false,
allow_email_password_login: false,
allow_public_access: true,
},
plugin_installation_permission: {

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "بحث عن مجموعات وأعضاء",
"accessControlDialog.title": "التحكم في الوصول إلى تطبيق الويب",
"accessControlDialog.updateSuccess": "تم التحديث بنجاح",
"accessControlDialog.webAppPublicAccessDisabledTip": "تم تعطيل الوصول العام من قبل مسؤول المؤسسة.",
"accessControlDialog.webAppSSONotEnabledTip": "الرجاء الاتصال بمسؤول المؤسسة لتكوين المصادقة الخارجية لتطبيق الويب.",
"accessItemsDescription.anyone": "يمكن لأي شخص الوصول إلى تطبيق الويب (لا يلزم تسجيل الدخول)",
"accessItemsDescription.external": "يمكن فقط للمستخدمين الخارجيين authenticated الوصول إلى تطبيق الويب",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Gruppen und Mitglieder suchen",
"accessControlDialog.title": "Zugriffskontrolle für Webanwendungen",
"accessControlDialog.updateSuccess": "Erfolgreich aktualisiert",
"accessControlDialog.webAppPublicAccessDisabledTip": "Der öffentliche Zugriff wurde von Ihrem Administrator deaktiviert.",
"accessControlDialog.webAppSSONotEnabledTip": "Bitte kontaktieren Sie den Unternehmensadministrator, um die Authentifizierungsmethode der Webanwendung zu konfigurieren.",
"accessItemsDescription.anyone": "Jeder kann auf die Webanwendung zugreifen.",
"accessItemsDescription.external": "Nur authentifizierte externe Benutzer können auf die Webanwendung zugreifen.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Search groups and members",
"accessControlDialog.title": "Web App Access Control",
"accessControlDialog.updateSuccess": "Update successfully",
"accessControlDialog.webAppPublicAccessDisabledTip": "Public access has been disabled by your administrator.",
"accessControlDialog.webAppSSONotEnabledTip": "Please contact your organization administrator to configure external authentication for the web app.",
"accessItemsDescription.anyone": "Anyone can access the web app (no login required)",
"accessItemsDescription.external": "Only authenticated external users can access the web app",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Buscar grupos y miembros",
"accessControlDialog.title": "Control de Acceso a la Aplicación Web",
"accessControlDialog.updateSuccess": "Actualización exitosa",
"accessControlDialog.webAppPublicAccessDisabledTip": "El acceso público ha sido deshabilitado por su administrador.",
"accessControlDialog.webAppSSONotEnabledTip": "Por favor, contacte al administrador de la empresa para configurar el método de autenticación de la aplicación web.",
"accessItemsDescription.anyone": "Cualquiera puede acceder a la aplicación web.",
"accessItemsDescription.external": "Solo los usuarios externos autenticados pueden acceder a la aplicación web.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "گروه‌ها و اعضا را جستجو کنید",
"accessControlDialog.title": "کنترل دسترسی به وب اپلیکیشن",
"accessControlDialog.updateSuccess": "به‌روز رسانی با موفقیت انجام شد",
"accessControlDialog.webAppPublicAccessDisabledTip": "دسترسی عمومی توسط مدیر شما غیرفعال شده است.",
"accessControlDialog.webAppSSONotEnabledTip": "لطفاً با مدیر شرکت تماس بگیرید تا روش احراز هویت برنامه وب را پیکربندی کند.",
"accessItemsDescription.anyone": "هر کسی می‌تواند به وب‌اپلیکیشن دسترسی پیدا کند",
"accessItemsDescription.external": "تنها کاربران خارجی تأیید شده می‌توانند به برنامه وب دسترسی پیدا کنند.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Rechercher des groupes et des membres",
"accessControlDialog.title": "Contrôle d'accès à l'application Web",
"accessControlDialog.updateSuccess": "Mise à jour réussie",
"accessControlDialog.webAppPublicAccessDisabledTip": "L'accès public a été désactivé par votre administrateur.",
"accessControlDialog.webAppSSONotEnabledTip": "Veuillez contacter l'administrateur de l'entreprise pour configurer la méthode d'authentification de l'application web.",
"accessItemsDescription.anyone": "Tout le monde peut accéder à l'application web.",
"accessItemsDescription.external": "Seuls les utilisateurs externes authentifiés peuvent accéder à l'application Web.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "समूहों और सदस्यों की खोज करें",
"accessControlDialog.title": "वेब एप्लिकेशन पहुँच नियंत्रण",
"accessControlDialog.updateSuccess": "सफलता से अपडेट किया गया",
"accessControlDialog.webAppPublicAccessDisabledTip": "सार्वजनिक पहुंच आपके व्यवस्थापक द्वारा अक्षम कर दी गई है।",
"accessControlDialog.webAppSSONotEnabledTip": "कृपया वेब ऐप प्रमाणीकरण विधि कॉन्फ़िगर करने के लिए उद्यम प्रशासक से संपर्क करें।",
"accessItemsDescription.anyone": "कोई भी वेब ऐप तक पहुँच सकता है",
"accessItemsDescription.external": "केवल प्रमाणित बाहरी उपयोगकर्ता वेब अनुप्रयोग तक पहुँच सकते हैं",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Cari grup dan anggota",
"accessControlDialog.title": "Kontrol Akses Aplikasi Web",
"accessControlDialog.updateSuccess": "Update berhasil",
"accessControlDialog.webAppPublicAccessDisabledTip": "Akses publik telah dinonaktifkan oleh administrator Anda.",
"accessControlDialog.webAppSSONotEnabledTip": "Hubungi administrator organisasi Anda untuk mengonfigurasi autentikasi eksternal untuk aplikasi web.",
"accessItemsDescription.anyone": "Siapa pun dapat mengakses aplikasi web (tidak perlu login)",
"accessItemsDescription.external": "Hanya pengguna eksternal yang diautentikasi yang dapat mengakses aplikasi web",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Cerca gruppi e membri",
"accessControlDialog.title": "Controllo di accesso all'app web",
"accessControlDialog.updateSuccess": "Aggiornamento avvenuto con successo",
"accessControlDialog.webAppPublicAccessDisabledTip": "L'accesso pubblico è stato disabilitato dall'amministratore.",
"accessControlDialog.webAppSSONotEnabledTip": "Si prega di contattare l'amministratore dell'impresa per configurare il metodo di autenticazione dell'app web.",
"accessItemsDescription.anyone": "Chiunque può accedere all'app web",
"accessItemsDescription.external": "Solo gli utenti esterni autenticati possono accedere all'applicazione Web",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "グループやメンバーを検索",
"accessControlDialog.title": "アクセス権限",
"accessControlDialog.updateSuccess": "更新が成功しました",
"accessControlDialog.webAppPublicAccessDisabledTip": "パブリックアクセスは管理者によって無効化されています。",
"accessControlDialog.webAppSSONotEnabledTip": "Web アプリの外部認証方式を設定するには、組織の管理者にお問い合わせください。",
"accessItemsDescription.anyone": "誰でもこの web アプリにアクセスできます(ログイン不要)",
"accessItemsDescription.external": "認証済みの外部ユーザーのみがこの Web アプリにアクセスできます",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "그룹 및 구성원 검색",
"accessControlDialog.title": "웹 애플리케이션 접근 제어",
"accessControlDialog.updateSuccess": "업데이트가 성공적으로 완료되었습니다.",
"accessControlDialog.webAppPublicAccessDisabledTip": "공개 액세스가 관리자에 의해 비활성화되었습니다.",
"accessControlDialog.webAppSSONotEnabledTip": "웹 앱 인증 방법을 구성하려면 엔터프라이즈 관리자인에게 문의하십시오.",
"accessItemsDescription.anyone": "누구나 웹 앱에 접근할 수 있습니다.",
"accessItemsDescription.external": "인증된 외부 사용자만 웹 애플리케이션에 접근할 수 있습니다.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Search groups and members",
"accessControlDialog.title": "Web App Access Control",
"accessControlDialog.updateSuccess": "Update successfully",
"accessControlDialog.webAppPublicAccessDisabledTip": "Public access has been disabled by your administrator.",
"accessControlDialog.webAppSSONotEnabledTip": "Please contact your organization administrator to configure external authentication for the web app.",
"accessItemsDescription.anyone": "Anyone can access the web app (no login required)",
"accessItemsDescription.external": "Only authenticated external users can access the web app",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Szukaj grup i członków",
"accessControlDialog.title": "Kontrola dostępu do aplikacji internetowej",
"accessControlDialog.updateSuccess": "Aktualizacja powiodła się",
"accessControlDialog.webAppPublicAccessDisabledTip": "Dostęp publiczny został wyłączony przez administratora.",
"accessControlDialog.webAppSSONotEnabledTip": "Proszę skontaktować się z administratorem przedsiębiorstwa, aby skonfigurować metodę uwierzytelniania aplikacji internetowej.",
"accessItemsDescription.anyone": "Każdy może uzyskać dostęp do aplikacji webowej",
"accessItemsDescription.external": "Tylko uwierzytelnieni zewnętrzni użytkownicy mogą uzyskać dostęp do aplikacji internetowej.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Pesquisar grupos e membros",
"accessControlDialog.title": "Controle de Acesso do Aplicativo Web",
"accessControlDialog.updateSuccess": "Atualização bem-sucedida",
"accessControlDialog.webAppPublicAccessDisabledTip": "O acesso público foi desativado pelo administrador.",
"accessControlDialog.webAppSSONotEnabledTip": "Por favor, entre em contato com o administrador da empresa para configurar o método de autenticação da aplicação web.",
"accessItemsDescription.anyone": "Qualquer pessoa pode acessar o aplicativo web",
"accessItemsDescription.external": "Apenas usuários externos autenticados podem acessar o aplicativo Web.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Caută grupuri și membri",
"accessControlDialog.title": "Controlul Accesului la Aplicația Web",
"accessControlDialog.updateSuccess": "Actualizare reușită",
"accessControlDialog.webAppPublicAccessDisabledTip": "Accesul public a fost dezactivat de administratorul dumneavoastră.",
"accessControlDialog.webAppSSONotEnabledTip": "Vă rugăm să contactați administratorul de întreprindere pentru a configura metoda de autentificare a aplicației web.",
"accessItemsDescription.anyone": "Oricine poate accesa aplicația web",
"accessItemsDescription.external": "Numai utilizatorii externi autentificați pot accesa aplicația web",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Искать группы и участников",
"accessControlDialog.title": "Управление доступом к веб-приложению",
"accessControlDialog.updateSuccess": "Обновление прошло успешно",
"accessControlDialog.webAppPublicAccessDisabledTip": "Публичный доступ был отключён администратором.",
"accessControlDialog.webAppSSONotEnabledTip": "Пожалуйста, свяжитесь с администратором предприятия, чтобы настроить метод аутентификации веб-приложения.",
"accessItemsDescription.anyone": "Любой может получить доступ к веб-приложению",
"accessItemsDescription.external": "Только аутентифицированные внешние пользователи могут получить доступ к веб-приложению.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Išči skupine in člane",
"accessControlDialog.title": "Nadzor dostopa do spletne aplikacije",
"accessControlDialog.updateSuccess": "Posodobitev uspešna",
"accessControlDialog.webAppPublicAccessDisabledTip": "Javni dostop je onemogočil skrbnik.",
"accessControlDialog.webAppSSONotEnabledTip": "Prosimo, da se obrnete na skrbnika podjetja, da konfigurira način avtentikacije spletne aplikacije.",
"accessItemsDescription.anyone": "Vsakdo lahko dostopa do spletne aplikacije",
"accessItemsDescription.external": "Samo avtentificirani zunanji uporabniki lahko dostopajo do spletne aplikacije.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "ค้นหากลุ่มและสมาชิก",
"accessControlDialog.title": "การควบคุมการเข้าถึงเว็บแอปพลิเคชัน",
"accessControlDialog.updateSuccess": "อัปเดตสำเร็จแล้ว",
"accessControlDialog.webAppPublicAccessDisabledTip": "การเข้าถึงแบบสาธารณะถูกปิดใช้งานโดยผู้ดูแลระบบของคุณ",
"accessControlDialog.webAppSSONotEnabledTip": "กรุณาติดต่อผู้ดูแลระบบองค์กรเพื่อกำหนดวิธีการตรวจสอบสิทธิ์แอปเว็บ.",
"accessItemsDescription.anyone": "ใครก็สามารถเข้าถึงเว็บแอปได้",
"accessItemsDescription.external": "ผู้ใช้งานภายนอกที่ได้รับการยืนยันตัวตนเท่านั้นที่สามารถเข้าถึงแอปพลิเคชันเว็บได้",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Grupları ve üyeleri ara",
"accessControlDialog.title": "Web Uygulaması Erişim Kontrolü",
"accessControlDialog.updateSuccess": "Başarıyla güncellendi",
"accessControlDialog.webAppPublicAccessDisabledTip": "Genel erişim yöneticiniz tarafından devre dışı bırakıldı.",
"accessControlDialog.webAppSSONotEnabledTip": "Lütfen web uygulaması kimlik doğrulama yöntemini yapılandırmak için kurumsal yöneticinizle iletişime geçin.",
"accessItemsDescription.anyone": "Herkes web uygulamasına erişebilir",
"accessItemsDescription.external": "Sadece kimliği doğrulanmış dış kullanıcılar Web uygulamasına erişebilir",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Шукати групи та учасників",
"accessControlDialog.title": "Контроль доступу до веб-додатка",
"accessControlDialog.updateSuccess": "Оновлення успішно",
"accessControlDialog.webAppPublicAccessDisabledTip": "Публічний доступ вимкнено адміністратором.",
"accessControlDialog.webAppSSONotEnabledTip": "Будь ласка, зв'яжіться з адміністратором підприємства для налаштування методу аутентифікації веб-додатку.",
"accessItemsDescription.anyone": "Будь-хто може отримати доступ до веб-додатку",
"accessItemsDescription.external": "Тільки перевірені зовнішні користувачі можуть отримати доступ до веб-застосунку.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Tìm kiếm nhóm và thành viên",
"accessControlDialog.title": "Kiểm soát truy cập ứng dụng web",
"accessControlDialog.updateSuccess": "Cập nhật thành công",
"accessControlDialog.webAppPublicAccessDisabledTip": "Quyền truy cập công khai đã bị quản trị viên vô hiệu hóa.",
"accessControlDialog.webAppSSONotEnabledTip": "Vui lòng liên hệ với quản trị viên doanh nghiệp để cấu hình phương thức xác thực ứng dụng web.",
"accessItemsDescription.anyone": "Mọi người đều có thể truy cập ứng dụng web.",
"accessItemsDescription.external": "Chỉ những người dùng bên ngoài đã xác thực mới có thể truy cập vào ứng dụng Web.",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "搜索组或成员",
"accessControlDialog.title": "Web 应用访问权限",
"accessControlDialog.updateSuccess": "更新成功",
"accessControlDialog.webAppPublicAccessDisabledTip": "公开访问已被管理员禁用。",
"accessControlDialog.webAppSSONotEnabledTip": "请联系企业管理员配置 Web 应用外部认证方式。",
"accessItemsDescription.anyone": "任何人都可以访问该 web 应用(无需登录)",
"accessItemsDescription.external": "仅经认证的外部用户可访问该 Web 应用",

View File

@ -17,6 +17,7 @@
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "搜尋群組和成員",
"accessControlDialog.title": "網頁應用程式存取控制",
"accessControlDialog.updateSuccess": "更新成功",
"accessControlDialog.webAppPublicAccessDisabledTip": "公開存取已被管理員停用。",
"accessControlDialog.webAppSSONotEnabledTip": "請聯絡企業管理員配置網頁應用程式的身份驗證方法。",
"accessItemsDescription.anyone": "任何人都可以訪問這個網絡應用程式",
"accessItemsDescription.external": "只有經過身份驗證的外部用戶才能訪問該網絡應用程序",