mirror of
https://github.com/langgenius/dify.git
synced 2026-07-21 18:58:35 +08:00
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:
parent
ed1289281d
commit
62bbc0dbeb
@ -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,
|
||||
|
||||
@ -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 |
|
||||
|
||||
@ -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 |
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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: '' },
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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: '' },
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
|
||||
@ -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()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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', [])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -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'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "بحث عن مجموعات وأعضاء",
|
||||
"accessControlDialog.title": "التحكم في الوصول إلى تطبيق الويب",
|
||||
"accessControlDialog.updateSuccess": "تم التحديث بنجاح",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "تم تعطيل الوصول العام من قبل مسؤول المؤسسة.",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "الرجاء الاتصال بمسؤول المؤسسة لتكوين المصادقة الخارجية لتطبيق الويب.",
|
||||
"accessItemsDescription.anyone": "يمكن لأي شخص الوصول إلى تطبيق الويب (لا يلزم تسجيل الدخول)",
|
||||
"accessItemsDescription.external": "يمكن فقط للمستخدمين الخارجيين authenticated الوصول إلى تطبيق الويب",
|
||||
|
||||
@ -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.",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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.",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "گروهها و اعضا را جستجو کنید",
|
||||
"accessControlDialog.title": "کنترل دسترسی به وب اپلیکیشن",
|
||||
"accessControlDialog.updateSuccess": "بهروز رسانی با موفقیت انجام شد",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "دسترسی عمومی توسط مدیر شما غیرفعال شده است.",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "لطفاً با مدیر شرکت تماس بگیرید تا روش احراز هویت برنامه وب را پیکربندی کند.",
|
||||
"accessItemsDescription.anyone": "هر کسی میتواند به وباپلیکیشن دسترسی پیدا کند",
|
||||
"accessItemsDescription.external": "تنها کاربران خارجی تأیید شده میتوانند به برنامه وب دسترسی پیدا کنند.",
|
||||
|
||||
@ -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.",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "समूहों और सदस्यों की खोज करें",
|
||||
"accessControlDialog.title": "वेब एप्लिकेशन पहुँच नियंत्रण",
|
||||
"accessControlDialog.updateSuccess": "सफलता से अपडेट किया गया",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "सार्वजनिक पहुंच आपके व्यवस्थापक द्वारा अक्षम कर दी गई है।",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "कृपया वेब ऐप प्रमाणीकरण विधि कॉन्फ़िगर करने के लिए उद्यम प्रशासक से संपर्क करें।",
|
||||
"accessItemsDescription.anyone": "कोई भी वेब ऐप तक पहुँच सकता है",
|
||||
"accessItemsDescription.external": "केवल प्रमाणित बाहरी उपयोगकर्ता वेब अनुप्रयोग तक पहुँच सकते हैं",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "グループやメンバーを検索",
|
||||
"accessControlDialog.title": "アクセス権限",
|
||||
"accessControlDialog.updateSuccess": "更新が成功しました",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "パブリックアクセスは管理者によって無効化されています。",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "Web アプリの外部認証方式を設定するには、組織の管理者にお問い合わせください。",
|
||||
"accessItemsDescription.anyone": "誰でもこの web アプリにアクセスできます(ログイン不要)",
|
||||
"accessItemsDescription.external": "認証済みの外部ユーザーのみがこの Web アプリにアクセスできます",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "그룹 및 구성원 검색",
|
||||
"accessControlDialog.title": "웹 애플리케이션 접근 제어",
|
||||
"accessControlDialog.updateSuccess": "업데이트가 성공적으로 완료되었습니다.",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "공개 액세스가 관리자에 의해 비활성화되었습니다.",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "웹 앱 인증 방법을 구성하려면 엔터프라이즈 관리자인에게 문의하십시오.",
|
||||
"accessItemsDescription.anyone": "누구나 웹 앱에 접근할 수 있습니다.",
|
||||
"accessItemsDescription.external": "인증된 외부 사용자만 웹 애플리케이션에 접근할 수 있습니다.",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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.",
|
||||
|
||||
@ -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.",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Искать группы и участников",
|
||||
"accessControlDialog.title": "Управление доступом к веб-приложению",
|
||||
"accessControlDialog.updateSuccess": "Обновление прошло успешно",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "Публичный доступ был отключён администратором.",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "Пожалуйста, свяжитесь с администратором предприятия, чтобы настроить метод аутентификации веб-приложения.",
|
||||
"accessItemsDescription.anyone": "Любой может получить доступ к веб-приложению",
|
||||
"accessItemsDescription.external": "Только аутентифицированные внешние пользователи могут получить доступ к веб-приложению.",
|
||||
|
||||
@ -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.",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "ค้นหากลุ่มและสมาชิก",
|
||||
"accessControlDialog.title": "การควบคุมการเข้าถึงเว็บแอปพลิเคชัน",
|
||||
"accessControlDialog.updateSuccess": "อัปเดตสำเร็จแล้ว",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "การเข้าถึงแบบสาธารณะถูกปิดใช้งานโดยผู้ดูแลระบบของคุณ",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "กรุณาติดต่อผู้ดูแลระบบองค์กรเพื่อกำหนดวิธีการตรวจสอบสิทธิ์แอปเว็บ.",
|
||||
"accessItemsDescription.anyone": "ใครก็สามารถเข้าถึงเว็บแอปได้",
|
||||
"accessItemsDescription.external": "ผู้ใช้งานภายนอกที่ได้รับการยืนยันตัวตนเท่านั้นที่สามารถเข้าถึงแอปพลิเคชันเว็บได้",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "Шукати групи та учасників",
|
||||
"accessControlDialog.title": "Контроль доступу до веб-додатка",
|
||||
"accessControlDialog.updateSuccess": "Оновлення успішно",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "Публічний доступ вимкнено адміністратором.",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "Будь ласка, зв'яжіться з адміністратором підприємства для налаштування методу аутентифікації веб-додатку.",
|
||||
"accessItemsDescription.anyone": "Будь-хто може отримати доступ до веб-додатку",
|
||||
"accessItemsDescription.external": "Тільки перевірені зовнішні користувачі можуть отримати доступ до веб-застосунку.",
|
||||
|
||||
@ -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.",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "搜索组或成员",
|
||||
"accessControlDialog.title": "Web 应用访问权限",
|
||||
"accessControlDialog.updateSuccess": "更新成功",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "公开访问已被管理员禁用。",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "请联系企业管理员配置 Web 应用外部认证方式。",
|
||||
"accessItemsDescription.anyone": "任何人都可以访问该 web 应用(无需登录)",
|
||||
"accessItemsDescription.external": "仅经认证的外部用户可访问该 Web 应用",
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"accessControlDialog.operateGroupAndMember.searchPlaceholder": "搜尋群組和成員",
|
||||
"accessControlDialog.title": "網頁應用程式存取控制",
|
||||
"accessControlDialog.updateSuccess": "更新成功",
|
||||
"accessControlDialog.webAppPublicAccessDisabledTip": "公開存取已被管理員停用。",
|
||||
"accessControlDialog.webAppSSONotEnabledTip": "請聯絡企業管理員配置網頁應用程式的身份驗證方法。",
|
||||
"accessItemsDescription.anyone": "任何人都可以訪問這個網絡應用程式",
|
||||
"accessItemsDescription.external": "只有經過身份驗證的外部用戶才能訪問該網絡應用程序",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user