diff --git a/api/configs/enterprise/__init__.py b/api/configs/enterprise/__init__.py index 3aeffe4c0f4..ecce58193b8 100644 --- a/api/configs/enterprise/__init__.py +++ b/api/configs/enterprise/__init__.py @@ -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, diff --git a/api/openapi/markdown/console-openapi.md b/api/openapi/markdown/console-openapi.md index 94bd31486ce..41b486f21a3 100644 --- a/api/openapi/markdown/console-openapi.md +++ b/api/openapi/markdown/console-openapi.md @@ -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, **Default:** true | | Yes | | allow_sso | boolean | | Yes | | enabled | boolean | | Yes | | sso_config | [WebAppAuthSSOModel](#webappauthssomodel) | | Yes | diff --git a/api/openapi/markdown/web-openapi.md b/api/openapi/markdown/web-openapi.md index 521c126d5b0..44296235014 100644 --- a/api/openapi/markdown/web-openapi.md +++ b/api/openapi/markdown/web-openapi.md @@ -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, **Default:** true | | Yes | | allow_sso | boolean | | Yes | | enabled | boolean | | Yes | | sso_config | [WebAppAuthSSOModel](#webappauthssomodel) | | Yes | diff --git a/api/services/feature_service.py b/api/services/feature_service.py index f8d69073458..de72792f4d5 100644 --- a/api/services/feature_service.py +++ b/api/services/feature_service.py @@ -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 diff --git a/api/tests/unit_tests/services/test_feature_service_webapp_public_access.py b/api/tests/unit_tests/services/test_feature_service_webapp_public_access.py new file mode 100644 index 00000000000..a58aa44d323 --- /dev/null +++ b/api/tests/unit_tests/services/test_feature_service_webapp_public_access.py @@ -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 diff --git a/packages/contracts/generated/api/console/system-features/types.gen.ts b/packages/contracts/generated/api/console/system-features/types.gen.ts index eaf6a11fb87..0417727f5ba 100644 --- a/packages/contracts/generated/api/console/system-features/types.gen.ts +++ b/packages/contracts/generated/api/console/system-features/types.gen.ts @@ -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 diff --git a/packages/contracts/generated/api/console/system-features/zod.gen.ts b/packages/contracts/generated/api/console/system-features/zod.gen.ts index 402a485925d..3ce9d68841e 100644 --- a/packages/contracts/generated/api/console/system-features/zod.gen.ts +++ b/packages/contracts/generated/api/console/system-features/zod.gen.ts @@ -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: '' }, diff --git a/packages/contracts/generated/api/web/types.gen.ts b/packages/contracts/generated/api/web/types.gen.ts index ad578e8381a..607386d387d 100644 --- a/packages/contracts/generated/api/web/types.gen.ts +++ b/packages/contracts/generated/api/web/types.gen.ts @@ -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 diff --git a/packages/contracts/generated/api/web/zod.gen.ts b/packages/contracts/generated/api/web/zod.gen.ts index 093722ed9cc..4dec23a2fe5 100644 --- a/packages/contracts/generated/api/web/zod.gen.ts +++ b/packages/contracts/generated/api/web/zod.gen.ts @@ -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: '' }, diff --git a/web/app/components/app/app-access-control/__tests__/access-control-item.spec.tsx b/web/app/components/app/app-access-control/__tests__/access-control-item.spec.tsx index 16b389155dd..2bd51a9a2d2 100644 --- a/web/app/components/app/app-access-control/__tests__/access-control-item.spec.tsx +++ b/web/app/components/app/app-access-control/__tests__/access-control-item.spec.tsx @@ -47,4 +47,25 @@ describe('AccessControlItem', () => { expect(anyone).toBeChecked() }) + + it('should not select a disabled option', async () => { + const user = userEvent.setup() + render( + aria-label="Access" defaultValue={AccessMode.PUBLIC}> + + Organization Only + + Anyone + , + ) + + 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() + }) }) diff --git a/web/app/components/app/app-access-control/__tests__/index.spec.tsx b/web/app/components/app/app-access-control/__tests__/index.spec.tsx index d273ddb0ad8..e83d8730fd2 100644 --- a/web/app/components/app/app-access-control/__tests__/index.spec.tsx +++ b/web/app/components/app/app-access-control/__tests__/index.spec.tsx @@ -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( + , + ) + + 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( + , + ) + + const publicOption = screen.getByRole('radio', { + name: /app\.accessControlDialog\.accessItems\.anyone/, + }) + expect(publicOption).toHaveAttribute('aria-disabled', 'true') + expect( + screen.getByLabelText('app.accessControlDialog.webAppPublicAccessDisabledTip'), + ).toBeInTheDocument() + }) + }) }) diff --git a/web/app/components/app/app-access-control/access-control-item.tsx b/web/app/components/app/app-access-control/access-control-item.tsx index 446fb67ca6e..f4f5d3bb03c 100644 --- a/web/app/components/app/app-access-control/access-control-item.tsx +++ b/web/app/components/app/app-access-control/access-control-item.tsx @@ -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 ( value={type} + disabled={disabled} render={} 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} diff --git a/web/app/components/app/app-access-control/index.tsx b/web/app/components/app/app-access-control/index.tsx index f443b80fa72..89a2bac6574 100644 --- a/web/app/components/app/app-access-control/index.tsx +++ b/web/app/components/app/app-access-control/index.tsx @@ -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 ( @@ -117,19 +130,29 @@ export default function AccessControl(props: AccessControlProps) { {!hideTip && } - + {t(($) => $['accessControlDialog.accessItems.anyone'], { ns: 'app' })} + {publicAccessDisabled && ( + $['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' })} + + )} {t(($) => $['operation.cancel'], { ns: 'common' })} 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( + , + 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( + , + 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', []) + }) + }) }) diff --git a/web/features/deployments/detail/access/permissions/__tests__/permissions.spec.tsx b/web/features/deployments/detail/access/permissions/__tests__/permissions.spec.tsx index a14be0ea474..d5ef6b45449 100644 --- a/web/features/deployments/detail/access/permissions/__tests__/permissions.spec.tsx +++ b/web/features/deployments/detail/access/permissions/__tests__/permissions.spec.tsx @@ -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'], + }, + }, }, })) diff --git a/web/features/deployments/detail/access/permissions/access-control-dialog.tsx b/web/features/deployments/detail/access/permissions/access-control-dialog.tsx index 70c48539e3f..3d4cfafa797 100644 --- a/web/features/deployments/detail/access/permissions/access-control-dialog.tsx +++ b/web/features/deployments/detail/access/permissions/access-control-dialog.tsx @@ -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(() => 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} /> - + {t(($) => $['accessControlDialog.accessItems.anyone'], { ns: 'app' })} + {publicAccessDisabled && ( + $['accessControlDialog.webAppPublicAccessDisabledTip'], { + ns: 'app', + })} + className="size-3.5 shrink-0 text-text-warning-secondary hover:text-text-warning-secondary" + > + {t(($) => $['accessControlDialog.webAppPublicAccessDisabledTip'], { ns: 'app' })} + + )} @@ -168,12 +184,15 @@ function DeploymentAccessControlDialogBody({ function AccessControlItem({ type, children, + disabled, }: PropsWithChildren<{ type: AppAccessMode + disabled?: boolean }>) { return ( value={type} + disabled={disabled} render={} 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', diff --git a/web/features/system-features/config.ts b/web/features/system-features/config.ts index df9c6a93c8f..764574c0e55 100644 --- a/web/features/system-features/config.ts +++ b/web/features/system-features/config.ts @@ -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: { diff --git a/web/i18n/ar-TN/app.json b/web/i18n/ar-TN/app.json index 34508c37d48..ba03eac9757 100644 --- a/web/i18n/ar-TN/app.json +++ b/web/i18n/ar-TN/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "بحث عن مجموعات وأعضاء", "accessControlDialog.title": "التحكم في الوصول إلى تطبيق الويب", "accessControlDialog.updateSuccess": "تم التحديث بنجاح", + "accessControlDialog.webAppPublicAccessDisabledTip": "تم تعطيل الوصول العام من قبل مسؤول المؤسسة.", "accessControlDialog.webAppSSONotEnabledTip": "الرجاء الاتصال بمسؤول المؤسسة لتكوين المصادقة الخارجية لتطبيق الويب.", "accessItemsDescription.anyone": "يمكن لأي شخص الوصول إلى تطبيق الويب (لا يلزم تسجيل الدخول)", "accessItemsDescription.external": "يمكن فقط للمستخدمين الخارجيين authenticated الوصول إلى تطبيق الويب", diff --git a/web/i18n/de-DE/app.json b/web/i18n/de-DE/app.json index b9b03b187c1..efe2a7c505e 100644 --- a/web/i18n/de-DE/app.json +++ b/web/i18n/de-DE/app.json @@ -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.", diff --git a/web/i18n/en-US/app.json b/web/i18n/en-US/app.json index 6cf49527888..b6e401f58c7 100644 --- a/web/i18n/en-US/app.json +++ b/web/i18n/en-US/app.json @@ -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", diff --git a/web/i18n/es-ES/app.json b/web/i18n/es-ES/app.json index 3d48ec71970..12e1d0fdcd5 100644 --- a/web/i18n/es-ES/app.json +++ b/web/i18n/es-ES/app.json @@ -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.", diff --git a/web/i18n/fa-IR/app.json b/web/i18n/fa-IR/app.json index 62f366cdcac..3b207895ef1 100644 --- a/web/i18n/fa-IR/app.json +++ b/web/i18n/fa-IR/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "گروهها و اعضا را جستجو کنید", "accessControlDialog.title": "کنترل دسترسی به وب اپلیکیشن", "accessControlDialog.updateSuccess": "بهروز رسانی با موفقیت انجام شد", + "accessControlDialog.webAppPublicAccessDisabledTip": "دسترسی عمومی توسط مدیر شما غیرفعال شده است.", "accessControlDialog.webAppSSONotEnabledTip": "لطفاً با مدیر شرکت تماس بگیرید تا روش احراز هویت برنامه وب را پیکربندی کند.", "accessItemsDescription.anyone": "هر کسی میتواند به وباپلیکیشن دسترسی پیدا کند", "accessItemsDescription.external": "تنها کاربران خارجی تأیید شده میتوانند به برنامه وب دسترسی پیدا کنند.", diff --git a/web/i18n/fr-FR/app.json b/web/i18n/fr-FR/app.json index 75d7d2ec6c3..e69e4b4dc32 100644 --- a/web/i18n/fr-FR/app.json +++ b/web/i18n/fr-FR/app.json @@ -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.", diff --git a/web/i18n/hi-IN/app.json b/web/i18n/hi-IN/app.json index e28ba534997..90147fcac5c 100644 --- a/web/i18n/hi-IN/app.json +++ b/web/i18n/hi-IN/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "समूहों और सदस्यों की खोज करें", "accessControlDialog.title": "वेब एप्लिकेशन पहुँच नियंत्रण", "accessControlDialog.updateSuccess": "सफलता से अपडेट किया गया", + "accessControlDialog.webAppPublicAccessDisabledTip": "सार्वजनिक पहुंच आपके व्यवस्थापक द्वारा अक्षम कर दी गई है।", "accessControlDialog.webAppSSONotEnabledTip": "कृपया वेब ऐप प्रमाणीकरण विधि कॉन्फ़िगर करने के लिए उद्यम प्रशासक से संपर्क करें।", "accessItemsDescription.anyone": "कोई भी वेब ऐप तक पहुँच सकता है", "accessItemsDescription.external": "केवल प्रमाणित बाहरी उपयोगकर्ता वेब अनुप्रयोग तक पहुँच सकते हैं", diff --git a/web/i18n/id-ID/app.json b/web/i18n/id-ID/app.json index edab40930cb..bf074839b9c 100644 --- a/web/i18n/id-ID/app.json +++ b/web/i18n/id-ID/app.json @@ -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", diff --git a/web/i18n/it-IT/app.json b/web/i18n/it-IT/app.json index fd714dfa1ed..5b86b42b580 100644 --- a/web/i18n/it-IT/app.json +++ b/web/i18n/it-IT/app.json @@ -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", diff --git a/web/i18n/ja-JP/app.json b/web/i18n/ja-JP/app.json index c9b9605ce0c..0b590709dc7 100644 --- a/web/i18n/ja-JP/app.json +++ b/web/i18n/ja-JP/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "グループやメンバーを検索", "accessControlDialog.title": "アクセス権限", "accessControlDialog.updateSuccess": "更新が成功しました", + "accessControlDialog.webAppPublicAccessDisabledTip": "パブリックアクセスは管理者によって無効化されています。", "accessControlDialog.webAppSSONotEnabledTip": "Web アプリの外部認証方式を設定するには、組織の管理者にお問い合わせください。", "accessItemsDescription.anyone": "誰でもこの web アプリにアクセスできます(ログイン不要)", "accessItemsDescription.external": "認証済みの外部ユーザーのみがこの Web アプリにアクセスできます", diff --git a/web/i18n/ko-KR/app.json b/web/i18n/ko-KR/app.json index 90685884e2d..d25a798b681 100644 --- a/web/i18n/ko-KR/app.json +++ b/web/i18n/ko-KR/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "그룹 및 구성원 검색", "accessControlDialog.title": "웹 애플리케이션 접근 제어", "accessControlDialog.updateSuccess": "업데이트가 성공적으로 완료되었습니다.", + "accessControlDialog.webAppPublicAccessDisabledTip": "공개 액세스가 관리자에 의해 비활성화되었습니다.", "accessControlDialog.webAppSSONotEnabledTip": "웹 앱 인증 방법을 구성하려면 엔터프라이즈 관리자인에게 문의하십시오.", "accessItemsDescription.anyone": "누구나 웹 앱에 접근할 수 있습니다.", "accessItemsDescription.external": "인증된 외부 사용자만 웹 애플리케이션에 접근할 수 있습니다.", diff --git a/web/i18n/nl-NL/app.json b/web/i18n/nl-NL/app.json index a163edb5d05..ed2efd4e209 100644 --- a/web/i18n/nl-NL/app.json +++ b/web/i18n/nl-NL/app.json @@ -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", diff --git a/web/i18n/pl-PL/app.json b/web/i18n/pl-PL/app.json index 8b19839850a..a16e77d8954 100644 --- a/web/i18n/pl-PL/app.json +++ b/web/i18n/pl-PL/app.json @@ -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.", diff --git a/web/i18n/pt-BR/app.json b/web/i18n/pt-BR/app.json index 77656b93672..e21bf87982e 100644 --- a/web/i18n/pt-BR/app.json +++ b/web/i18n/pt-BR/app.json @@ -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.", diff --git a/web/i18n/ro-RO/app.json b/web/i18n/ro-RO/app.json index 5536ba4d444..f7c88b96574 100644 --- a/web/i18n/ro-RO/app.json +++ b/web/i18n/ro-RO/app.json @@ -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", diff --git a/web/i18n/ru-RU/app.json b/web/i18n/ru-RU/app.json index a1cb0c8a5b5..e6250d5324a 100644 --- a/web/i18n/ru-RU/app.json +++ b/web/i18n/ru-RU/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "Искать группы и участников", "accessControlDialog.title": "Управление доступом к веб-приложению", "accessControlDialog.updateSuccess": "Обновление прошло успешно", + "accessControlDialog.webAppPublicAccessDisabledTip": "Публичный доступ был отключён администратором.", "accessControlDialog.webAppSSONotEnabledTip": "Пожалуйста, свяжитесь с администратором предприятия, чтобы настроить метод аутентификации веб-приложения.", "accessItemsDescription.anyone": "Любой может получить доступ к веб-приложению", "accessItemsDescription.external": "Только аутентифицированные внешние пользователи могут получить доступ к веб-приложению.", diff --git a/web/i18n/sl-SI/app.json b/web/i18n/sl-SI/app.json index ad510e3b2fd..feab5823004 100644 --- a/web/i18n/sl-SI/app.json +++ b/web/i18n/sl-SI/app.json @@ -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.", diff --git a/web/i18n/th-TH/app.json b/web/i18n/th-TH/app.json index cb23186aa7a..b9592f5e190 100644 --- a/web/i18n/th-TH/app.json +++ b/web/i18n/th-TH/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "ค้นหากลุ่มและสมาชิก", "accessControlDialog.title": "การควบคุมการเข้าถึงเว็บแอปพลิเคชัน", "accessControlDialog.updateSuccess": "อัปเดตสำเร็จแล้ว", + "accessControlDialog.webAppPublicAccessDisabledTip": "การเข้าถึงแบบสาธารณะถูกปิดใช้งานโดยผู้ดูแลระบบของคุณ", "accessControlDialog.webAppSSONotEnabledTip": "กรุณาติดต่อผู้ดูแลระบบองค์กรเพื่อกำหนดวิธีการตรวจสอบสิทธิ์แอปเว็บ.", "accessItemsDescription.anyone": "ใครก็สามารถเข้าถึงเว็บแอปได้", "accessItemsDescription.external": "ผู้ใช้งานภายนอกที่ได้รับการยืนยันตัวตนเท่านั้นที่สามารถเข้าถึงแอปพลิเคชันเว็บได้", diff --git a/web/i18n/tr-TR/app.json b/web/i18n/tr-TR/app.json index 8903f2179c9..80e8d13536b 100644 --- a/web/i18n/tr-TR/app.json +++ b/web/i18n/tr-TR/app.json @@ -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", diff --git a/web/i18n/uk-UA/app.json b/web/i18n/uk-UA/app.json index ef097eda0d0..792097ec84c 100644 --- a/web/i18n/uk-UA/app.json +++ b/web/i18n/uk-UA/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "Шукати групи та учасників", "accessControlDialog.title": "Контроль доступу до веб-додатка", "accessControlDialog.updateSuccess": "Оновлення успішно", + "accessControlDialog.webAppPublicAccessDisabledTip": "Публічний доступ вимкнено адміністратором.", "accessControlDialog.webAppSSONotEnabledTip": "Будь ласка, зв'яжіться з адміністратором підприємства для налаштування методу аутентифікації веб-додатку.", "accessItemsDescription.anyone": "Будь-хто може отримати доступ до веб-додатку", "accessItemsDescription.external": "Тільки перевірені зовнішні користувачі можуть отримати доступ до веб-застосунку.", diff --git a/web/i18n/vi-VN/app.json b/web/i18n/vi-VN/app.json index 23942758429..ad4dced0e69 100644 --- a/web/i18n/vi-VN/app.json +++ b/web/i18n/vi-VN/app.json @@ -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.", diff --git a/web/i18n/zh-Hans/app.json b/web/i18n/zh-Hans/app.json index 7fdb6c76522..b36b13a9511 100644 --- a/web/i18n/zh-Hans/app.json +++ b/web/i18n/zh-Hans/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "搜索组或成员", "accessControlDialog.title": "Web 应用访问权限", "accessControlDialog.updateSuccess": "更新成功", + "accessControlDialog.webAppPublicAccessDisabledTip": "公开访问已被管理员禁用。", "accessControlDialog.webAppSSONotEnabledTip": "请联系企业管理员配置 Web 应用外部认证方式。", "accessItemsDescription.anyone": "任何人都可以访问该 web 应用(无需登录)", "accessItemsDescription.external": "仅经认证的外部用户可访问该 Web 应用", diff --git a/web/i18n/zh-Hant/app.json b/web/i18n/zh-Hant/app.json index 1c844c45cad..37b4234b28f 100644 --- a/web/i18n/zh-Hant/app.json +++ b/web/i18n/zh-Hant/app.json @@ -17,6 +17,7 @@ "accessControlDialog.operateGroupAndMember.searchPlaceholder": "搜尋群組和成員", "accessControlDialog.title": "網頁應用程式存取控制", "accessControlDialog.updateSuccess": "更新成功", + "accessControlDialog.webAppPublicAccessDisabledTip": "公開存取已被管理員停用。", "accessControlDialog.webAppSSONotEnabledTip": "請聯絡企業管理員配置網頁應用程式的身份驗證方法。", "accessItemsDescription.anyone": "任何人都可以訪問這個網絡應用程式", "accessItemsDescription.external": "只有經過身份驗證的外部用戶才能訪問該網絡應用程序",
{t(($) => $['accessControlDialog.accessItems.anyone'], { ns: 'app' })}